Swift property observers, initial value - swift

The Apple documentation states:
The willSet and didSet observers of superclass properties are called when a property is set in a subclass initializer, after the superclass initializer has been called. They are not called while a class is setting its own properties, before the superclass initializer has been called.
which means if I have some type:
enum State {
case disabled, enabled
}
and some variable that has a willSet or didSet observer:
var state: State = .disabled {
willSet {
// do something
}
}
the willSet observer won't get called until after I explicitly set state in during or after initialization of that particular instance.
Why does it work this way? As a developer, I would look at the above code and make the assumption, not unreasonably, that the observer block gets called for the original value, irrespective of instance initialization. It seems like one heck of an anti-pattern to have to set state = .disabled in the initializer to trigger the observer for the initial value.

As Hamish's comment points out, in the case of willSet there's not a valid value that state could have here (and in the case of didSet, there's not a valid value the newValue argument could have).

There's no restriction on whether willSet/didSet can access other properties of the instance. For that reason, all the instance properties need to be properly initialised before any observers are called.
On top of that, if the observer didSet was called when first setting a property's value, the oldValue variable would contain garbage, as it would never have been set.

The way properties are handled in Swift is roughly analogous to the recommended behavior for initialization in Objective-C, notably the section "Don't Use Accessors in Initializer Methods and Dealloc" found on this page. If you set a property foo in your init method, it's equivalent to setting the _foo instance variable in Objective-C, whereas setting foo outside of init is analogous to calling foo's accessors. Basically, what used to be considered a best practice is now actually enforced by the compiler.
The reason for this is to avoid aberrant side effects caused by accessors assuming that the rest of the object's state is set up already, when in actuality it is not.
This can be worked around fairly easily, though; you can make a fooDidSet() method, call that from within foo's didSet, and then also call it at the end of your initializer after calling super's designated init. Alternatively, you can just set the property to itself after calling super's init to cause its didSet to fire.

Think what would happen in a situation like this:
class Person {
var firstName: String {
didSet {
print("New full name:", firstName, lastName)
}
}
var lastName: String {
didSet {
print("New full name:", firstName, lastName)
}
}
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
}
You'd end up using an uninitalized value for lastName. Which can could very well crash the app.
Swift wants to ensure object integrity, and executing observers from init can't guarantee this, as observers have access to all class members.

Related

Is it possible to initialize properties at the beginning of a class?

I am writing my project and wondered.
When I read literature or watch videos, I see that this is bad practice. Why? Is this bad for the system?
What is the difference between this
class SomeClass {
var someView = SomeView()
var someViewModel = SomeViewModel()
// ...
}
and this
class SomeClass {
var someView: SomeView!
var someViewModel: SomeViewModel?
// ...
}
How to get used to it better?
You have to initialize all instance properties somehow. And you have to do it right up front, either in the declaration line or in your init method.
But what if you don't actually have the initial value until later, like in viewDidLoad? Then it is silly to supply a real heavyweight value only to replace it later:
var v = MyView()
override func viewDidLoad() {
self.v = // get _real_ MyView and assign it in place of that
}
Instead, we use an Optional to mark the fact that we have no value yet; until we obtain and assign one, it will be nil:
var v : MyView? // means it is initially `nil`
override func viewDidLoad() {
self.v = // get _real_ MyView and assign it to our property
}
There's nothing wrong with the first way (which is called a "default property value", by the way), and in fact, often times it's preferable. But of course, the devil is in the details:
How would the initialization of a SomeViewModel work? Without acess the initializer parameters of SomeClass, you're stuck with only being able to construct an instance from a parameter-less init, like SomeViewModel(). What exactly could that do? Suppose it was a person view model, and you had PersonViewModel(). What person? Whats their name? What will this default value do at all?
It's not a great pattern if it requires overwriting the default value with some other value in the initializer
It initializes the value up-front, where sometimes a lazy or computed value might be more appropriate.

ReactiveSwift mutable property with read only public access

I have a class with enum property state. This property's value (by value I mean ReactiveSwift.Property's value) needs to be accessed and observed by other classes, but value change should be private. Currently it is implemented in a such way:
enum State {
case stopped, running, paused
}
var state: Property<State> {
return Property(mutableState)
}
fileprivate let mutableState = MutableProperty<State>(.stopped)
This pattern allows me to modify mutableState property within class file. At the same time outside the class state is available only for reading and observing.
The question is whether there is a way to implement a similar thing using single property? Also probably someone can suggest a better pattern for the same solution?
I can't think of any way to do this with a single property. The only adjustment I would make to your code is to make state a stored property rather than a computed property that gets newly created each time it is accessed:
class Foo {
let state: Property<State>
fileprivate let mutableState = MutableProperty<State>(.stopped)
init() {
state = Property(mutableState)
}
}
Depending where you want to mutate the state, you can try doing either of:
private(set) var state: Property<State>
or if you modify it from an extension but still the same file
fileprivate(set) var state: Property<State>

Understanding optional global variables in swift

I'm working through a book on Swift and I understand the idea of scope in functions so what I'd like to understand next is why we set global variables using optional types in classes. Honestly it looks like we don't set these variables per say but just let the class know that there will be a variable of a specific type somewhere throughout the code base: var sut: ItemManager!.
From what I understand the variable sut is an unwrapped optional of the type ItemManger which definitely has a valid value and not nil. The reason we've set it with an exclamation mark or question mark is because there isn't an initializer within this class. What isn't clear is since this class doesn't have an initializer, what factors come into play when deciding weather to set this global variable to an optional using a questions mark or implicitly unwrapped with an exclamation mark?
import XCTest
#testable import ToDo
class ItemManagerTests: XCTestCase {
var sut: ItemManager!
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
sut = ItemManager.init()
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func test_ToDoCount_InitiallySetAtZero(){
let sut = ItemManager.init()
XCTAssertEqual(sut.toDoCount, 0)
}
func test_DoneCount_InitiallySetAtZero(){
let sut = ItemManager.init()
XCTAssertEqual(sut.doneCount, 0)
}
}
sut is not a global variable.
sut is an instance variable of the ItemManagerTests. Every time a new instance, i.e. an object, of a ItemManagerTests is instantiated, memory is allocated for sut.
It's of type ItemManager!. This is an implicitly unwrapped optional. It's similar to ItemManager? (a.k.a. Optional), with the distinction that it is implicitly forcefully unwrapped everywhere it's used directly, as if the force unwrap operator (!) was used.
Its value is initialized to nil, but is set to a new ItemManager object when setUp is called by Xcode's testing framework.
Firstly, sut is not a global. A global variable in Swift is declared outside any enclosing scope (So, before the class statement). sut is an instance property; each instance of your ItemManagerTests class will have a sut property.
In Swift, all non-optional properties must be initialised by the time the initialiser has completed. In some cases this can be achieved by code inside the initialiser and in other cases by assigning a default value.
In some cases, s you cannot assign or don't want to assign a default value and you can't (or don't want to) override the initialiser.
If you used a normal optional then the compiler would be satisfied that the property wasn't initialised by default or in the initialiser, but each time you referred to the property you would have to unwrap it (e.g. sut?.donecount).
Since your test case is assigning a value to sut in setup, you know that it will have a value and you could use a force unwrap (e.g. sut!.donecount), or, take it one step further and use an implicitly unwrapped optional. This allows you to refer to the property without any unwrapping, but it is still an optional and will still cause a crash if it is nil.
Note that your current code isn't even using the property, since you are allocating a local variable in your test cases. You can use:
class ItemManagerTests: XCTestCase {
var sut: ItemManager!
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
sut = ItemManager.init()
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func test_ToDoCount_InitiallySetAtZero() {
XCTAssertEqual(sut.toDoCount, 0)
}
func test_DoneCount_InitiallySetAtZero() {
XCTAssertEqual(sut.doneCount, 0)
}
}
The reason we've set it with an exclamation mark or question mark is
because there isn't an initializer within this class
Because when every instance of a class is initialized, it has to allocate memory for its properties/instance var. So with var sut: ItemManager!, the value of sut is nil when init. Without !, ? the compiler can't allocate, init, so you have to init manually in an initializer. That is what compiler told you.
For using ! or ?.
! is used when the property/var always has value after the first assigning. And after the first time it's assigned, it can't be nil later
? is used when the pro/var can have value or not

Confused on closure strong reference cycle?

class HTMLElement {
let name : String
let text: String?
//Declaring a lazy variable that has a strong reference to this closure
lazy var asHTML: Void -> String = {
//Optional binding here
if let text = self.text {
return "<\(self.name)>\(text)<\(self.name)>"
} else {
return "<\(self.name) >"
}
}
init(name: String, text: String? = nil){
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
My Question is: Why is the closure declared Lazy, I know it has something to do with self not being known in the closure, but isn't that the same case for the init method where self hasn't been created?
Secondly,Where exactly is the strong reference cycle in this code example, is it self that strongly references to asHTML, if so where is the second part of the strong referencing that causes the cycle?
Third, Why is the constant text property an optional when constants cannot change value(from nil to a value and back to nil)?
Lastly, What does it mean to have the parameter text: String? = nil in the init method when the init method is used to accept parameters sent by the user?
Sorry for this long question, I'm just confused on the closure strong reference cycle....although I do understand strong reference cycles between class properties and class instances.
1
lazy is used for attributes that are only created when called upon. So before you call myClass.myLazyAttribute it will not take up any space. This also means that it will init after the class has initialised, which can be very useful.
In this case lazy is used to get access to self, like you stated, because self is not available until the instance has been initialised.
2
The apple doc from where code is.
Closures capture the values used in them. In this case it captures self.
It does not create a Strong Reference Cycle between class A and class B, but between itself and a closure. It makes a lot more sense if you imagine that the operation inside the closure takes a very long time. During the execution something else has happened and you want to deinit the instance. But the closure has captured self and it will keep the instance alive until it is done.
By using [unowned self] in you can again deinit the instance while the closure is running. Although this will crash your app.
good info on this specific use : link
In the specific case of a closure, you just need to realize that any variable that is referenced inside of it, gets "owned" by the closure. As long as the closure is around, those objects are guaranteed to be around. The only way to stop that ownership, is to do the [unowned self] or [weak self].
What a Strong Reference Cycle in essence is:
you have an instance of a class
the instance has a reference count higher than 0
there is no longer a reference to the instance available to your program.
Or even shorter: the reference count of the instance is higher than the number of accessible references.
In this case the reference count of self goes up by 1 because it is captured by the closure. We can not access that reference because we can not say something like: closure.selfAttribute, so we can not set that to nil. Only when the closure is finished will the reference count go down by 1 again.
3
It is an optional constant, but it's initial value is set in the init method of the class. So it can receive a value in the init method, but it will be immutable. This is called a late init.
4
This is a function parameter with a default value.
func someFunction(myParamWithDefaultValue : Int = 10) {
print(myParamWithDefaultValue)
}
someFunction() // 10
someFunction(5) // 5

What is the purpose of willSet and didSet in Swift?

Swift has a property declaration syntax very similar to C#'s:
var foo: Int {
get { return getFoo() }
set { setFoo(newValue) }
}
However, it also has willSet and didSet actions. These are called before and after the setter is called, respectively. What is their purpose, considering that you could just have the same code inside the setter?
The point seems to be that sometimes, you need a property that has automatic storage and some behavior, for instance to notify other objects that the property just changed. When all you have is get/set, you need another field to hold the value. With willSet and didSet, you can take action when the value is modified without needing another field. For instance, in that example:
class Foo {
var myProperty: Int = 0 {
didSet {
print("The value of myProperty changed from \(oldValue) to \(myProperty)")
}
}
}
myProperty prints its old and new value every time it is modified. With just getters and setters, I would need this instead:
class Foo {
var myPropertyValue: Int = 0
var myProperty: Int {
get { return myPropertyValue }
set {
print("The value of myProperty changed from \(myPropertyValue) to \(newValue)")
myPropertyValue = newValue
}
}
}
So willSet and didSet represent an economy of a couple of lines, and less noise in the field list.
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 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
}
}
}
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 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
}
}
}
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!
You can also use the didSet to set the variable to a different value. This does not cause the observer to be called again as stated in Properties guide. For example, it is useful when you want to limit the value as below:
let minValue = 1
var value = 1 {
didSet {
if value < minValue {
value = minValue
}
}
}
value = -10 // value is minValue now.
These are called 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.
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/ca/jEUH0.l
I suspect it's to allow for things we would traditionally do with KVO such as data binding with UI elements, or triggering side effects of changing a property, triggering a sync process, background processing, etc, etc.
NOTE
willSet and didSet observers are not called when a property is set in an initializer before delegation takes place
The many well-written existing answers cover the question well, but I'll mention, in some detail, an addition that I believe is worth covering.
The willSet and didSet property observers can be used to call delegates, e.g., for class properties that are only ever updated by user interaction, but where you want to avoid calling the delegate at object initialization.
I'll cite Klaas up-voted comment to the accepted answer:
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.
This is a quite neat as it means e.g. the didSet property is a good choice of launch point for delegate callbacks & functions, for your own custom classes.
As an example, consider some custom user control object, with some key property value (e.g. position in rating control), implemented as a subclass of 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.
}
After which your delegate functions can be used in, say, some view controller to observe key changes in the model for CustomViewController, much like you'd use the inherent delegate functions of the UITextFieldDelegate for UITextField objects (e.g. textFieldDidEndEditing(...)).
For this simple example, use a delegate callback from the didSet of the class property value to tell a view controller that one of it's outlets have had associated model update:
// 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 ...
//}
}
Here, the value property has been encapsulated, but generally: in situations like these, be careful not to update the value property of the customUserControl object in the scope of the associated delegate function (here: didChangeValue()) in the view controller, or you'll end up with infinite recursion.
The willSet and didSet observers for the properties whenever the property is assigned a new value. This is true even if the new value is the same as the current value.
And note that willSet needs a parameter name to work around, on the other hand, didSet does not.
The didSet observer is called after the value of property is updated. It compares against the old value. If the total number of steps has increased, a message is printed to indicate how many new steps have been taken. The didSet observer does not provide a custom parameter name for the old value, and the default name of oldValue is used instead.
Getter and setter are sometimes too heavy to implement just to observe proper value changes. Usually this needs extra temporary variable handling and extra checks, and you will want to avoid even those tiny labour if you write hundreds of getters and setters. These stuffs are for the situation.
In your own (base) class, willSet and didSet are quite reduntant , as you could instead define a calculated property (i.e get- and set- methods) that access a _propertyVariable and does the desired pre- and post- prosessing.
If, however, you override a class where the property is already defined, then the willSet and didSet are useful and not redundant!
One thing where didSet is really handy is when you use outlets to add additional configuration.
#IBOutlet weak var loginOrSignupButton: UIButton! {
didSet {
let title = NSLocalizedString("signup_required_button")
loginOrSignupButton.setTitle(title, for: .normal)
loginOrSignupButton.setTitle(title, for: .highlighted)
}
I do not know C#, but with a little guesswork I think I understand what
foo : int {
get { return getFoo(); }
set { setFoo(newValue); }
}
does. It looks very similar to what you have in Swift, but it's not the same: in Swift you do not have the getFoo and setFoo. That is not a little difference: it means you do not have any underlying storage for your value.
Swift has stored and computed properties.
A computed property has get and may have set (if it's writable). But the code in the getter and setter, if they need to actually store some data, must do it in other properties. There is no backing storage.
A stored property, on the other hand, does have backing storage. But it does not have get and set. Instead it has willSet and didSet which you can use to observe variable changes and, eventually, trigger side effects and/or modify the stored value. You do not have willSet and didSet for computed properties, and you do not need them because for computed properties you can use the code in set to control changes.