Quantcast
Channel: What is the purpose of willSet and didSet in Swift? - Stack Overflow
Viewing all articles
Browse latest Browse all 12

Answer by user3675131 for What is the purpose of willSet and didSet in Swift?

$
0
0

My understanding is that set and get are for computed properties (no backing from stored properties)

if you are coming from an Objective-C bare in mind that the naming conventions have changed. In Swift an iVar or instance variable is named stored property

Example 1 (read only property) - with warning:

var test : Int {    get {        return test    }}

This will result in a warning because this results in a recursive function call (the getter calls itself).The warning in this case is "Attempting to modify 'test' within its own getter".

Example 2. Conditional read/write - with warning

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        }    }}

Similar problem - you cannot do this as it's recursively calling the setter.Also, note this code will not complain about no initialisers as there is no stored property to initialise.

Example 3. read/write computed property - with backing store

Here is a pattern that allows conditional setting of an actual stored property
//True model datavar _test : Int = 0var test : Int {    get {        return _test    }    set (aNewValue) {        //I've contrived some condition on which this property can be set        if (aNewValue != test) {            _test = aNewValue        }    }}

Note The actual data is called _test (although it could be any data or combination of data)Note also the need to provide an initial value (alternatively you need to use an init method) because _test is actually an instance variable

Example 4. Using will and did set

//True model datavar _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        }    }}

Here we see willSet and didSet intercepting a change in an actual stored property.This is useful for sending notifications, synchronisation etc... (see example below)

Example 5. Concrete Example - ViewController Container

//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        }    }}

Note the use of BOTH computed and stored properties. I've used a computed property to prevent setting the same value twice (to avoid bad things happening!); I've used willSet and didSet to forward notifications to viewControllers (see UIViewController documentation and info on viewController containers)

If I've made a mistake anywhere, please edit to fix it!


Viewing all articles
Browse latest Browse all 12

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>