Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: how to change a property's value without calling its didSet function

Tags:

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; 
like image 428
ctpenrose Avatar asked Aug 19 '14 22:08

ctpenrose


People also ask

What is difference between willSet and didSet in Swift?

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.

Is didSet called on initialization?

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.

What does didSet mean in Swift?

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.

What is property Observer in Swift?

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.


2 Answers

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

like image 72
Warren Burton Avatar answered Sep 23 '22 22:09

Warren Burton


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.

like image 31
Sergey Kalinichenko Avatar answered Sep 24 '22 22:09

Sergey Kalinichenko