How can you set a property's value in Swift, without calling its didSet()
function outside of an initialization context? The code below was a failed experiment to achieve this within the classes' noside()
function
class Test { var toggle : Bool = 0 var hoodwink : Int = 0 { didSet(hoodwink) { toggle = !toggle } } // failed attempt to set without a side effect func noside(newValue : Int) { hoodwink = newValue println("hoodwink: \(hoodwink) state: \(toggle)") } func withside(newValue : Int) { self.hoodwink = newValue println("hoodwink: \(hoodwink) state: \(toggle)") } }
It is quite trivial to do in Objective-C with auto-synthesized properties:
With side effect (if present in setter):
self.hoodwink = newValue;
Without side effect:
_hoodwink = newValue;
willSet is called before the data is actually changed and it has a default constant newValue which shows the value that is going to be set. didSet is called right after the data is stored and it has a default constant oldValue which shows the previous value that is overwritten.
willSet and didSet observers are not called when a property is first initialized. They are only called when the property's value is set outside of an initialization context.
In Swift, didSet and willSet methods act as property observers. willSet runs a piece of code right before a property changes. didSet runs a piece of code right after the property has changed.
Property Observers. Property observers observe and respond to changes in a property's value. Property observers are called every time a property's value is set, even if the new value is the same as the property's current value. You can add property observers in the following places: Stored properties that you define.
A possible hack around this is to provide a setter which bypasses your didSet
var dontTriggerObservers:Bool = false var selectedIndexPath:NSIndexPath? { didSet { if(dontTriggerObservers == false){ //blah blah things to do } } } var primitiveSetSelectedIndexPath:NSIndexPath? { didSet(indexPath) { dontTriggerObservers = true selectedIndexPath = indexPath dontTriggerObservers = false } }
Ugly but workable
What you do in Objective-C to "avoid side effects" is accessing the backing store of the property - its instance variable, which is prefixed with underscore by default (you can change this using the @synthesize
directive).
However, it looks like Swift language designers took specific care to make it impossible to access the backing variables for properties: according to the book,
If you have experience with Objective-C, you may know that it provides two ways to store values and references as part of a class instance. In addition to properties, you can use instance variables as a backing store for the values stored in a property.
Swift unifies these concepts into a single property declaration. A Swift property does not have a corresponding instance variable, and the backing store for a property is not accessed directly. (emphasis is mine)
Of course this applies only to using the "regular language" means, as opposed to using reflection: it might provide a way around this restriction, at the expense of readability.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With