swift - स्विफ्ट में इच्छा और क्या सेट का उद्देश्य क्या है?




(8)

स्विफ्ट में एक संपत्ति घोषणा वाक्यविन्यास है जो सी # के समान ही है:

var foo: Int {
    get { return getFoo() }
    set { setFoo(newValue) }
}

हालांकि, यह भी willSet और कार्य करता है didSet करें। इन्हें क्रमशः सेटर के नाम से पहले और बाद में बुलाया जाता है। उनका उद्देश्य क्या है, इस पर विचार करते हुए कि आप बसटर के अंदर एक ही कोड हो सकते हैं?


जब भी संपत्ति को एक नया मूल्य सौंपा जाता है तो संपत्तियों के लिए WillSet और didSet पर्यवेक्षक। यह सही है भले ही नया मान वर्तमान मान के समान है।

और ध्यान दें कि दूसरी तरफ काम करने के willSet को पैरामीटर नाम की आवश्यकता होगी, दूसरी तरफ, didSet नहीं करता है।

संपत्ति के मूल्य को अद्यतन करने के बाद डीडसेट पर्यवेक्षक को बुलाया जाता है। यह पुराने मूल्य के खिलाफ तुलना करता है। यदि चरणों की कुल संख्या में वृद्धि हुई है, तो यह संकेत करने के लिए एक संदेश मुद्रित किया गया है कि कितने नए कदम उठाए गए हैं। डीडसेट पर्यवेक्षक पुराने मान के लिए कस्टम पैरामीटर नाम प्रदान नहीं करता है, और इसके बजाय पुराने वैल्यू का डिफ़ॉल्ट नाम उपयोग किया जाता है।


ध्यान दें

प्रतिनिधिमंडल होने से पहले एक प्रारंभकर्ता में एक संपत्ति सेट होने पर पर्यवेक्षकों को बुलाया नहीं जाएगा


आप वैरिएबल को एक अलग मान पर सेट करने के लिए didSet का भी उपयोग कर सकते हैं। यह प्रॉपर्टी गाइड में बताए गए पर्यवेक्षक को फिर से बुलाया नहीं जाता है। उदाहरण के लिए, यह तब उपयोगी होता है जब आप निम्न मान को सीमित करना चाहते हैं:

let minValue = 1

var value = 1 {
    didSet {
        if value < minValue {
            value = minValue
        }
    }
}

value = -10 // value is minValue now.

इन्हें संपत्ति पर्यवेक्षक कहा जाता है:

संपत्ति पर्यवेक्षक संपत्ति के मूल्य में परिवर्तनों का निरीक्षण करते हैं और उनका जवाब देते हैं। संपत्ति पर्यवेक्षकों को हर बार एक संपत्ति का मूल्य निर्धारित किया जाता है, भले ही नया मान संपत्ति के वर्तमान मूल्य के समान ही हो।

से उद्धरण: ऐप्पल इंक "स्विफ्ट प्रोग्रामिंग भाषा।" IBooks। https://itun.es/ca/jEUH0.l

मुझे संदेह है कि यह उन चीजों की अनुमति देना है जो हम परंपरागत रूप से KVO साथ करते हैं जैसे यूआई तत्वों के साथ बाध्यकारी डेटा, या किसी संपत्ति को बदलने के दुष्प्रभावों को ट्रिगर करना, सिंक प्रक्रिया को ट्रिगर करना, पृष्ठभूमि प्रसंस्करण इत्यादि।


कई अच्छी तरह से लिखे गए मौजूदा उत्तरों में सवाल अच्छी तरह से शामिल है, लेकिन मैं कुछ विवरणों में उल्लेख करता हूं, एक अतिरिक्त जो मुझे विश्वास है कि कवर करने लायक है।

willSet और didSet प्रॉपर्टी पर्यवेक्षकों का उपयोग प्रतिनिधियों को कॉल करने के लिए किया जा सकता है, उदाहरण के लिए, क्लास गुणों के लिए जिन्हें केवल उपयोगकर्ता इंटरैक्शन द्वारा अपडेट किया जाता है, लेकिन जहां आप ऑब्जेक्ट प्रारंभिक पर प्रतिनिधि को कॉल करने से बचना चाहते हैं।

मैं स्वीकार किए गए उत्तर पर क्लास को वोट देने वाली टिप्पणी का हवाला दूंगा:

जब संपत्ति पहली बार शुरू की जाती है तो पर्यवेक्षकों को बुलाया नहीं जाता है। उन्हें केवल तभी बुलाया जाता है जब संपत्ति का मूल्य प्रारंभिक संदर्भ के बाहर सेट होता है।

यह काफी साफ है क्योंकि इसका मतलब है कि didSet संपत्ति प्रतिनिधि कॉलबैक और फ़ंक्शंस के लिए लॉन्च पॉइंट की एक अच्छी पसंद है, अपने स्वयं के कस्टम वर्गों के लिए।

उदाहरण के तौर पर, कुछ कस्टम प्रॉपर्टी value (उदाहरण के लिए रेटिंग नियंत्रण में स्थिति) के साथ कुछ कस्टम उपयोगकर्ता नियंत्रण ऑब्जेक्ट पर विचार करें, जो UIView उप-वर्ग के रूप में लागू किया गया है:

// CustomUserControl.swift
protocol CustomUserControlDelegate {
    func didChangeValue(value: Int)
    // func didChangeValue(newValue: Int, oldValue: Int)
    // func didChangeValue(customUserControl: CustomUserControl)
    // ... other more sophisticated delegate functions
}

class CustomUserControl: UIView {

    // Properties
    // ...
    private var value = 0 {
        didSet {
            // Possibly do something ...

            // Call delegate.
            delegate?.didChangeValue(value)
            // delegate?.didChangeValue(value, oldValue: oldValue)
            // delegate?.didChangeValue(self)
        }
    }

    var delegate: CustomUserControlDelegate?

    // Initialization
    required init?(...) { 
        // Initialise something ...

        // E.g. 'value = 1' would not call didSet at this point
    }

    // ... some methods/actions associated with your user control.
}

जिसके बाद आपके प्रतिनिधि कार्यों का उपयोग किया जा सकता है, कहें, कुछ दृश्य नियंत्रक CustomViewController लिए मॉडल में महत्वपूर्ण परिवर्तनों का निरीक्षण करने के लिए, जैसा कि आप UITextFieldDelegate के अंतर्निहित प्रतिनिधि कार्यों का उपयोग UITextField ऑब्जेक्ट्स (उदाहरण के लिए textFieldDidEndEditing(...) ) के लिए करेंगे। ।

इस सरल उदाहरण के लिए, क्लास प्रॉपर्टी value के didSet से एक प्रतिनिधि कॉलबैक का उपयोग एक व्यू कंट्रोलर को बताने के लिए करें कि उसके आउटलेट्स में से एक मॉडल अपडेट से जुड़ा हुआ है:

// ViewController.swift
Import UIKit
// ...

class ViewController: UIViewController, CustomUserControlDelegate {

    // Properties
    // ...
    @IBOutlet weak var customUserControl: CustomUserControl!

    override func viewDidLoad() {
        super.viewDidLoad()
        // ...

        // Custom user control, handle through delegate callbacks.
        customUserControl = self
    }

    // ...

    // CustomUserControlDelegate
    func didChangeValue(value: Int) {
        // do some stuff with 'value' ...
    }

    // func didChangeValue(newValue: Int, oldValue: Int) {
        // do some stuff with new as well as old 'value' ...
        // custom transitions? :)
    //}

    //func didChangeValue(customUserControl: CustomUserControl) {
    //    // Do more advanced stuff ...
    //}
}

यहां, value संपत्ति को समाहित किया गया है, लेकिन आम तौर पर: इन स्थितियों में, सावधान रहें, संबंधित नियंत्रक फ़ंक्शन (यहां: didChangeValue() ) के दायरे में customUserControl ऑब्जेक्ट की value संपत्ति को अद्यतन न करने के लिए सावधान रहें, या दृश्य नियंत्रक में, या आप अनंत रिकर्सन के साथ खत्म हो जाएगा।


गेटटर और सेटर कभी-कभी उचित मूल्य परिवर्तनों को देखने के लिए लागू करने के लिए बहुत भारी होते हैं। आम तौर पर इसे अतिरिक्त अस्थायी परिवर्तनीय हैंडलिंग और अतिरिक्त चेक की आवश्यकता होती है, और यदि आप सैकड़ों गेटर्स और सेटर्स लिखते हैं तो आप उन छोटे श्रम से बचना चाहेंगे। ये सामान स्थिति के लिए हैं।


मुझे सी # नहीं पता, लेकिन थोड़ा अनुमान लगाने के साथ मुझे लगता है कि मैं समझता हूं कि क्या

foo : int {
    get { return getFoo(); }
    set { setFoo(newValue); }
}

कर देता है। स्विफ्ट में आपके पास जो कुछ है, वह बहुत समान दिखता है, लेकिन यह वही नहीं है: स्विफ्ट में आपके पास getFoo और setFoo । यह थोड़ा अंतर नहीं है: इसका मतलब है कि आपके पास अपने मूल्य के लिए कोई अंतर्निहित भंडारण नहीं है।

स्विफ्ट ने संपत्तियों को संग्रहित और गणना की है।

एक गणना की गई संपत्ति get और हो सकती है (यदि यह लिखने योग्य है)। लेकिन गेटर और सेटर में कोड, अगर उन्हें वास्तव में कुछ डेटा स्टोर करने की आवश्यकता है, तो इसे अन्य गुणों में करना चाहिए। कोई बैकिंग स्टोरेज नहीं है।

दूसरी ओर, एक संग्रहित संपत्ति का बैकिंग स्टोरेज होता है। लेकिन यह get और set नहीं है। इसके बजाए यह willSet और किया didSet जिसे आप परिवर्तनीय परिवर्तनों का निरीक्षण करने के लिए उपयोग कर सकते हैं और अंत में, साइड इफेक्ट्स को ट्रिगर कर सकते हैं और / या संग्रहीत मूल्य को संशोधित कर सकते हैं। आपके पास willSet नहीं है और गणना की गई गुणों के लिए सेट करें, और आपको उनकी आवश्यकता नहीं है क्योंकि गणना की गई गुणों के लिए आप परिवर्तनों को नियंत्रित set लिए set में कोड का उपयोग कर सकते हैं।


मेरी समझ यह है कि सेट और प्राप्त गणना गुणों के लिए हैं ( संग्रहीत गुणों से कोई समर्थन नहीं)

यदि आप उद्देश्य-सी से आ रहे हैं तो ध्यान में रखते हुए कि नामकरण सम्मेलन बदल गए हैं। स्विफ्ट में एक iVar या इंस्टेंस वैरिएबल को संग्रहीत संपत्ति नाम दिया जाता है

उदाहरण 1 (केवल संपत्ति पढ़ें) - चेतावनी के साथ:

var test : Int {
    get {
        return test
    }
}

इसके परिणामस्वरूप एक चेतावनी होगी क्योंकि इसका परिणाम एक रिकर्सिव फ़ंक्शन कॉल (गेटटर कॉल स्वयं) में होता है। इस मामले में चेतावनी "अपने स्वयं के गेटटर के भीतर 'परीक्षण को संशोधित करने का प्रयास कर रही है"।

उदाहरण 2. चेतावनी के साथ सशर्त पढ़ने / लिखना

var test : Int {
    get {
        return test
    }
    set (aNewValue) {
        //I've contrived some condition on which this property can be set
        //(prevents same value being set)
        if (aNewValue != test) {
            test = aNewValue
        }
    }
}

इसी तरह की समस्या - आप इसे ऐसा नहीं कर सकते क्योंकि यह बार-बार सेटटर को कॉल कर रहा है। साथ ही, ध्यान दें कि यह कोड प्रारंभिक करने के लिए कोई संग्रहित संपत्ति नहीं है क्योंकि प्रारंभकर्ताओं के बारे में शिकायत नहीं करेगा।

उदाहरण 3. बैकिंग स्टोर के साथ - गणना की गई संपत्ति को पढ़ें / लिखें

यहां एक पैटर्न है जो वास्तविक संग्रहित संपत्ति की सशर्त सेटिंग की अनुमति देता है

//True model data
var _test : Int = 0

var test : Int {
    get {
        return _test
    }
    set (aNewValue) {
        //I've contrived some condition on which this property can be set
        if (aNewValue != test) {
            _test = aNewValue
        }
    }
}

नोट वास्तविक डेटा को _test कहा जाता है (हालांकि यह डेटा का कोई डेटा या संयोजन हो सकता है) नोट प्रारंभिक मान प्रदान करने की आवश्यकता भी है (वैकल्पिक रूप से आपको एक init विधि का उपयोग करने की आवश्यकता है) क्योंकि _test वास्तव में एक आवृत्ति चर है

उदाहरण 4. इच्छा और सेट का उपयोग करना

//True model data
var _test : Int = 0 {

    //First this
    willSet {
        println("Old value is \(_test), new value is \(newValue)")
    }

    //value is set

    //Finaly this
    didSet {
        println("Old value is \(oldValue), new value is \(_test)")
    }
}

var test : Int {
    get {
        return _test
    }
    set (aNewValue) {
        //I've contrived some condition on which this property can be set
        if (aNewValue != test) {
            _test = aNewValue
        }
    }
}

यहां हम देखेंगेसेट और रीसेट एक वास्तविक संग्रहीत संपत्ति में बदलाव को रोकना। यह सूचनाएं, सिंक्रनाइज़ेशन आदि भेजने के लिए उपयोगी है ... (नीचे उदाहरण देखें)

उदाहरण 5. कंक्रीट उदाहरण - व्यू कंट्रोलर कंटेनर

//Underlying instance variable (would ideally be private)
var _childVC : UIViewController? {
    willSet {
        //REMOVE OLD VC
        println("Property will set")
        if (_childVC != nil) {
            _childVC!.willMoveToParentViewController(nil)
            self.setOverrideTraitCollection(nil, forChildViewController: _childVC)
            _childVC!.view.removeFromSuperview()
            _childVC!.removeFromParentViewController()
        }
        if (newValue) {
            self.addChildViewController(newValue)
        }

    }

    //I can't see a way to 'stop' the value being set to the same controller - hence the computed property

    didSet {
        //ADD NEW VC
        println("Property did set")
        if (_childVC) {
//                var views  = NSDictionaryOfVariableBindings(self.view)    .. NOT YET SUPPORTED (NSDictionary bridging not yet available)

            //Add subviews + constraints
            _childVC!.view.setTranslatesAutoresizingMaskIntoConstraints(false)       //For now - until I add my own constraints
            self.view.addSubview(_childVC!.view)
            let views = ["view" : _childVC!.view] as NSMutableDictionary
            let layoutOpts = NSLayoutFormatOptions(0)
            let lc1 : AnyObject[] = NSLayoutConstraint.constraintsWithVisualFormat("|[view]|",  options: layoutOpts, metrics: NSDictionary(), views: views)
            let lc2 : AnyObject[] = NSLayoutConstraint.constraintsWithVisualFormat("V:|[view]|", options: layoutOpts, metrics: NSDictionary(), views: views)
            self.view.addConstraints(lc1)
            self.view.addConstraints(lc2)

            //Forward messages to child
            _childVC!.didMoveToParentViewController(self)
        }
    }
}


//Computed property - this is the property that must be used to prevent setting the same value twice
//unless there is another way of doing this?
var childVC : UIViewController? {
    get {
        return _childVC
    }
    set(suggestedVC) {
        if (suggestedVC != _childVC) {
            _childVC = suggestedVC
        }
    }
}

दोनों गणना और संग्रहीत गुणों के उपयोग पर ध्यान दें। मैंने एक ही मूल्य को दो बार सेट करने से रोकने के लिए एक गणना की गई संपत्ति का उपयोग किया है (बुरी चीजों से बचने के लिए!); मैंने कंट्रोलर को देखने के लिए अधिसूचनाओं को आगे बढ़ाने के लिए सेट किया है और किया है (देखें UIViewController दस्तावेज़ और दृश्य नियंत्रक कंटेनर पर जानकारी)

मुझे उम्मीद है कि यह मदद करता है, और अगर किसी ने यहां कहीं गलती की है तो कृपया चिल्लाओ!





swift