Quick question: why?
Context:
Am using Swinject dependency injection to add small-s singleton model classes to my views thus:
defaultContainer.registerForStoryboard( MyViewController.self )
{
responder, viewController in
viewController.proxy = responder.resolve( MyProxy.self )!
}
I want to guard against the risk of accidentally overwriting this singleton instance by using a computed property thus:
private var _proxy: MyProxy!
var proxy: MyProxy
{
set { if _proxy == nil { _proxy = newValue } }
}
But. I can't. Because I must also declare a getter.
Frustrating!
For now I am using the following hack. But really...
var proxy: MyProxy?
{
get { return nil }
set { if _proxy == nil && newValue != nil { _proxy = newValue } }
}
Depends on if the value you are talking about is something you want to let other classes modify - in some cases the answer is yes, in some it is no. If the answer is no then there is no reason to add a setter method and in fact it might harm things.
To create computed properties, Swift offers you a getter and (an optional) setter method to work with. A getter method is used to perform a computation when requested. A setter method is an optional method. It can be used to modify a related property.
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.
But what is the difference between a lazy variable and a computed property? A lazy variable is a stored property whose initialization is delayed. The initial value is computed only one time. A computed property is a value that is not stored anywhere.
A Swift property does not have a corresponding instance variable, and the backing store for a property is not accessed directly. This approach avoids confusion about how the value is accessed in different contexts and simplifies the property’s declaration into a single, definitive statement.
In C and Objective-C, you define static constants and variables associated with a type as global static variables. In Swift, however, type properties are written as part of the type’s definition, within the type’s outer curly braces, and each type property is explicitly scoped to the type it supports.
The getter is used to read the value, and the setter is used to write the value. The setter clause is optional, and when only a getter is needed, you can omit both clauses and simply return the requested value directly. That said, if you provide a setter clause, you must also provide a getter clause.
Although properties and methods declared in the superclass are inherited by the current class, designated initializers declared in the superclass are only inherited when the subclass meets the conditions described in Automatic Initializer Inheritance. Swift classes don’t inherit from a universal base class.
Once you add a get
(or set
) to a property, it turns into a Computed Property. Computed properties may be read-only, thus requiring only a get
ter, but they may not be write-only. So if you add a set
ter to a property, you turn it into a computer property hence you must add a getter as well.
EDIT: Following comments, Why can Computed Properties be read-only, but not write-only?
I can't find official documentation to back this up, so the following explanation is solely based on my logical point of view:
Computed Properties don't store actual data on their variables; instead they compute data to display.
var a:Int = 5 // Stored property
var timesTen:Int { // Computed Property
get {
return a * 10
}
}
From the example above: a
is a Stored property. Therefore, its get
method automatically returns a
's value. Now think of timesTen
: What's its value? Since it doesn't store any value in timesTen
variable, you must tell the computed property how and where to read its "value" from. So that's why you can't use a computed property for writing-only purposes.
For simple properties you may use didSet
or willSet
to achieve the desired purpose:
var proxy: MyProxy?
{
willSet { if _proxy == nil && newValue != nil { _proxy = newValue } }
}
If you are using Swift 2.x, you may use the guard
statement to for a cleaner code:
var proxy: MyProxy?
{
willSet {
guard (_proxy == nil && newValue != nil) else { return }
_proxy = newValue
}
}
If _proxy
is not required to be private
you may remove it completely, using only one variable/property instead of two:
var proxy: MyProxy!
{
willSet {
guard (proxy == nil && newValue != nil) else { return }
// By not preventing `willSet` to continue, `newValue` will automatically assigned to `proxy`
}
}
Why cant you just return _proxy
in your getter? What does that matter? If you are afraid of exposing your getter you can set your getter to private, thus exposing it only in the containing class.
private(get) var proxy: MyProxy? {
set { if _proxy == nil && newValue != nil { _proxy = newValue } }
}
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