Difference between computed property and property set with closure - swift

I'm new to Swift. What is the difference between a computed property and a property set to a closure? I know a computed property gets recalculated each time. Is it different for the closure? i.e.
Closure:
var pushBehavior: UIPushBehavior = {
let lazilyCreatedPush = UIPushBehavior()
lazilyCreatedPush.setAngle(50, magnitude: 50)
return lazilyCreatedPush
}()
Computed:
var pushBehavior: UIPushBehavior {
get{
let lazilyCreatedPush = UIPushBehavior()
lazilyCreatedPush.setAngle(50, magnitude: 50)
return lazilyCreatedPush
}
}

In short, the first is a stored property that is initialized via a closure, with that closure being called only one time, when it is initialized. The second is a computed property whose get block is called every time you reference that property.
The stored property’s initialization closure is called once and only once, but you can later change the value of the stored property (unless you replace var with let). This is useful when you want to encapsulate the code to initialize a stored property in a single, concise block of code.
The computed property’s block, however, is called each time you reference the variable. It’s useful when you want the code to be called every time you reference the computed property. Generally you do this when the computed property needs to be recalculated every time you reference the stored property (e.g. recalculated from other, possibly private, stored properties).
In this case, you undoubtedly want the stored property (the first example), not the computed property (the second example). You presumably don't want a new push behavior object each time you reference the variable.
By the way, in your first example, you internally reference to it being instantiated lazily. If you want that behavior, you must use the lazy keyword:
lazy var pushBehavior: UIPushBehavior = {
let behavior = UIPushBehavior()
behavior.setAngle(50, magnitude: 50)
return behavior
}()
If, however, the property is static, it is automatically instantiated lazily.

Closure :
//closure
var pushBehavior: UIPushBehavior = {
let lazilyCreatedPush = UIPushBehavior()
lazilyCreatedPush.setAngle(50, magnitude: 50)
return lazilyCreatedPush
}()
At first time when pushBehavior variable called then block execute and value is saved in pushBehavior variable. after that whenever you call pushBehavior then those value are returned.
means only first-time block code executed and saved in this variable.
Also, you can store variable value whenever you want but after that, those value returned but if you declare as "let" then you can't change this value.
Computed property :
var pushBehavior: UIPushBehavior {
get{
let lazilyCreatedPush = UIPushBehavior()
lazilyCreatedPush.setAngle(50, magnitude: 50)
return lazilyCreatedPush
}
}
In computed property whenever you called pushBehavior variable then this block execute and value return. so every time block is executed.
and you can not declare variable as "let" keyword for pushBehavior variable.
So you can use this code as per your requirement.

The main difference is that you cannot assign something to the computed property since it has no setter. In this case the closure only gets called once and the return value gets stored in the variable so if the outcome doesn't change over time it is more efficient to use the stored variable rather than the computed one.
In general: computed properties should only be used if the value can be retrieved quickly.
Sidenote: If you don't change/reassign the stored variable you should consider making it a constant (let)

This isn't an answer, but it's just worth mentioning that for:
A stored property's value must be known after initializing completes. That happens either by defaulting or through initialization.
A computed property's value isn't computed until it's accessed
A lazy loaded property's value isn't defined until it's accessed
Hence for both computed and lazy variables you can access self or stored properties with no worries.

Related

What is the advantage of closure stored property Initialisation?

What is the difference and the advantages/disadvantages of this code when initialising a property of a class as:
1.
let menuBar:MenuBar = {
let mb = MenuBar()
return mb
}()
and:
2.
let menuBar = MenuBar()
Both of the code snippets declare and initialize stored properties, but in the first one it is initialized by closure. The reason why you should set a stored property with a closure is: there is a requirement(s) to do customization (calling a method for instance); Adapted from The Swift Programming Language (Swift 4.1) - Initialization: Setting a Default Property Value with a Closure or Function:
If a stored property’s default value requires some customization or
setup, you can use a closure or global function to provide a
customized default value for that property. Whenever a new instance of
the type that the property belongs to is initialized, the closure or
function is called, and its return value is assigned as the property’s
default value.
Which means that you would be able to do:
let menuBar:MenuBar = {
let mb = MenuBar()
// for example, you'd need to call "doSomething" method
// before returning the instance:
menuBar.doSomething()
return mb
}()
Note that in the body of the stored property closure, you would be not able to able to use the other properties in your class/struct since they considered as not being initialized yet. Example:
struct MyType {
let myString = "My String!"
let myInt: Int = {
let anInt = 101
// this won't work
print(myString)
return anInt
}()
}
The result of the above code snippet is getting a compile-time error:
error: instance member 'myString' cannot be used on type 'MyType'
print(myString)
Furthermore at some point, it would be recommended to declare your property as lazy:
lazy var menuBar:MenuBar = {
let mb = MenuBar()
// for example, you'd need to call "doSomething" method
// before returning the instance:
menuBar.doSomething()
return mb
}()
Means that:
A lazy stored property is a property whose initial value is not
calculated until the first time it is used. You indicate a lazy stored
property by writing the lazy modifier before its declaration.

What's the point of READ-only variables when you have LET?

For example:
var dogName : String {
return "Buster"
}
VS..
let dogName = "Buster"
Let's say we're declaring each of these at the top level of a class as instance properties. Are these just two ways of doing the same thing? If not, what's the point of having a read-only variable?
Thanks
Let me try to sum up what the other answers are saying while also adding missing information that I think is critical in order to understand this.
Properties
Properties are simply values that are associated with an object and may be queried in a trivial amount of time without the need (or ability) for parameters like methods have.
Stored Properties
When you create a stored property, whether with let or var, the value assigned at any given point in time will be stored in memory, which is why it is called a stored property.
var name = "Matt"
For variables using var, the value is stored in memory in a way that makes it mutable (editable). You can reassign the value at will and it will replace the previous value stored in memory.
let name = "Matt"
For constants using let, the value is also stored in memory, but in such a way that it may not be changed after the first time assigning to it.
Computed Properties
Computed properties are not stored in memory. As ganzogo says in the comments, computed properties act similarly to methods, but do not take parameters. When deciding when to use a computed property or a function with no parameters, the Swift API Design Guidelines recommend using a computed property when it will simply create or fetch, and then return the value, provided that this takes a trivial amount of time.
var fullName: String {
return firstName + lastName
}
Here, we assume that firstName and lastName are already properties on the object. There is no sense of initialization with this property because it is not stored anywhere. It is fetched on demand every time. That is why there is no sense to doing anything like the following:
var dogName : String {
return "Buster"
}
This has no benefit over a stored property except that no memory will be used in storing the String "Buster".
In fact, this is a simplified version of computed properties. You will notice that the Swift Language Guide describes the use of both get and set in a computed property. set allows you to update the state of other variables when one sets a computed variable. For example:
var stored: Int
var computed: Int {
get {
return stored + 5
}
set {
stored = newValue - 5
}
}
Some useful applications of this were pointed out by Rajan's answer, for example getting and setting volume from width, height, and depth.
A read-only computed var is just a computed var which specifies only a getter, in which case the get keyword and brackets are not required.
Read-Only for Access Control
When developing modules such as frameworks, it is often useful to have a variable only be modifiable from within that object or framework and have it be read-only to the public.
private var modifiableItem: String
public var item: String {
return modifiableItem
}
The idea here is that modifiableItem should only be mutable from within the object that defined it. The private keyword ensures that it is only accessible within the scope of the object that created it and making it a var ensures that it may be modified. The public var item, then, is a computed variable that is exposed to the public that enables anyone to read, but not mutate the variable.
As Hamish notes in the comments, this is more concisely expressible by using private(set):
public private(set) var item: String
This is probably the best way to go about it, but the previous code (using a private stored property and public computed one) demonstrates the effect.
let dogName = "Buster"
means that the dogName variable can't be changed later on once assigned "Buster" and it becomes constant
var dogName : String {
return "Buster"
}
It is a computed read only property where you can have some calculation which can be changed as it is a var but in a way defined below:
The computed property can be changed like
var dogName : String {
return "Stress"+"Buster"
}
Consider this example from Apple Docs
struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0
var volume: Double {
return width * height * depth
}
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
It will print
// Prints "the volume of fourByFiveByTwo is 40.0"
Here the volume is calculated when you initialize the object of struct Cuboid and is computed at run time. If it was let, then you have to initialize it before using by some constant.
If you want to read more about it, read the Computed Properties section here
In your example, they are 2 ways of doing the same thing. However, you can do a lot more with a computed property. For example:
var dogName: String {
return firstName + " " + lastName
}
Here, firstName and lastName might not be known at initialization time. This is not possible to do with a simple let property.
It might help you to think of a computed property as a method with no parameters.
A read-only property in a class/struct means that you can't change the value of the property for that instance of the class/struct. It prevents me from doing:
someObject.dogName = "Buddy" // This fails - read-only property
However, I can still do this:
var someVariable = someObject.dogName // someVariable now is "Buster"
someVariable = "Buddy" // This is OK, it's now "Buddy"
A let constant means you won't be changing the value of that specific constant in that block of code.
let someName = "Buster"
someName = "Buddy" // This fails - someName is a constant
There are two different cases:
1) Value type:
struct DogValueType {
var name: String
}
let dog1 = DogValueType(name: "Buster")
var dog2: DogValueType {
return DogValueType(name: "Buster")
}
let dog3: DogValueType = {
return DogValueType(name: "Buster")
}()
dog1 - dog3 can't be changed or mutated
dog1 & dog3 stores value
dog3 computes value each time you accessing it
2) Reference type:
class DogReferenceType {
var name: String
init(name: String) {
self.name = name
}
}
let dog4 = DogReferenceType(name: "Buster")
var dog5: DogReferenceType {
return DogReferenceType(name: "Buster")
}
let dog6: DogReferenceType = {
return DogReferenceType(name: "Buster")
}()
dog4 - dog6 can't be changed, but can be mutated
dog4 & dog6 stores reference to an object.
dog5 creates object each time you accessing it

Capturing a struct reference in a closure doesn't allow mutations to occur

I am trying to see if I can use structs for my model and was trying this. When I call vm.testClosure(), it does not change the value of x and I am not sure why.
struct Model
{
var x = 10.0
}
var m = Model()
class ViewModel
{
let testClosure:() -> ()
init(inout model: Model)
{
testClosure =
{
() -> () in
model.x = 30.5
}
}
}
var vm = ViewModel(model:&m)
m.x
vm.testClosure()
m.x
An inout argument isn't a reference to a value type – it's simply a shadow copy of that value type, that is written back to the caller's value when the function returns.
What's happening in your code is that your inout variable is escaping the lifetime of the function (by being captured in a closure that is then stored) – meaning that any changes to the inout variable after the function has returned will never be reflected outside that closure.
Due to this common misconception about inout arguments, there has been a Swift Evolution proposal for only allowing inout arguments to be captured by #noescape closures. As of Swift 3, your current code will no longer compile.
If you really need to be passing around references in your code – then you should be using reference types (make your Model a class). Although I suspect that you'll probably be able to refactor your logic to avoid passing around references in the first place (however without seeing your actual code, it's impossible to advise).
(Edit: Since posting this answer, inout parameters can now be compiled as a pass-by-reference, which can be seen by looking at the SIL or IR emitted. However you are unable to treat them as such due to the fact that there's no guarantee whatsoever that the caller's value will remain valid after the function call.)
Instances of the closure will get their own, independent copy of the captured value that it, and only it, can alter. The value is captured in the time of executing the closure. Let see your slightly modified code
struct Model
{
var x = 10.0
mutating func modifyX(newValue: Double) {
let this = self
let model = m
x = newValue
// put breakpoint here
//(lldb) po model
//▿ Model
// - x : 30.0
//
//(lldb) po self
//▿ Model
// - x : 301.0
//
//(lldb) po this
//▿ Model
// - x : 30.0
}
}
var m = Model()
class ViewModel
{
let testClosure:() -> ()
init(inout model: Model)
{
model.x = 50
testClosure =
{ () -> () in
model.modifyX(301)
}
model.x = 30
}
}
let mx = m.x
vm.testClosure()
let mx2 = m.x
Here is what Apple says about that.
Classes and Structures
A value type is a type that is copied when it is assigned to a
variable or constant, or when it is passed to a function. [...] All
structures and enumerations are value types in Swift
Methods
Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.
However, if you need to modify the properties of your structure or
enumeration within a particular method, you can opt in to mutating
behaviour for that method. The method can then mutate (that is,
change) its properties from within the method, and any changes that it
makes are written back to the original structure when the method ends.
The method can also assign a completely new instance to its implicit
self property, and this new instance will replace the existing one
when the method ends.
Taken from here

Are computed properties evaluated every time they are accessed?

I have two questions about computed properties in Swift.
Are computed properties evaluated every time they are accessed? Or they are stored somewhere for future access?
What kind of property is this, since I couldn't google it out:
let navigationController: UINavigationController = {
var navigator = UINavigationController()
navigator.navigationBar.translucent = false
return navigator
}()
Is this also evaluated every time it is accessed?
That is NOT a computed property.
let navigationController: UINavigationController = {
var navigator = UINavigationController()
navigator.navigationBar.translucent = false
return navigator
}()
It is just a stored property populated with the result of the value returned by this block of code.
var navigator = UINavigationController()
navigator.navigationBar.translucent = false
return navigator
The block is executed when the instance of the class is instantiated. Only once.
So writing this
struct Person {
let name: String = {
let name = "Bob"
return name
}() // <- look at these
}
is equivalent to this
struct Person {
let name: String
init() {
self.name = "Bob"
}
}
IMHO the first approach is better because:
it does allow you to declared and populate a property in the same "space"
it's more clear
does prevent duplication of code if you have multiple initializers
Note #1: Storing a closure inside a property
As dfri noted in the comment below, the block of code does end with (). It means that the code is evaluated and the result assigned to the property.
On the other hand, if we remove the () at the end of the block, we get something different, infact the block is not evaluated.
In this case Swift tries to assign a stored closure to the property. This will produce a compile error since the property has this type UINavigationController.
With the correct syntax we can put a closure inside a property.
struct Person {
let sayHello: ()->() = { print("Hello") }
}
Now we have a sayHello property which contains a closure. The closure receives 0 parameters and does return Void.
let bob = Person()
bob.sayHello // this does NOT execute the code inside closure
bob.sayHello() // this does execute the code in the closure and does print the message
Note #2: let's talk about Computed Properties
So we made clear that code in this question is not a Computed Property.
However, as EmilioPelaez noted in another comment below, we should also state that a Computed Property is evaluated each time it is accessed.
In the example below I created a Computed Property age. As you can see each time I invoke it, the code in the block gets executed as well.
Example of a Computed Property (age)

Class instance variable initialization order?

Currently, I am seeing something strange behavior.
class DataManager1
{
let THE_ID = "SOME_ID_STRING"
let _con1 = CKContainer(identifier: THE_ID) // error
// error: 'DataManager1.Type' does not have a member named 'THE_ID'
}
class DataManager2
{
let THE_ID = "SOME_ID_STRING"
let _con1:CKContainer?
init()
{
_con1 = CKContainer(identifier: THE_ID) // no error.
}
}
In C++ we have a defined initialization order between instance member variables. I expected something similar, but actually I couldn't find a mention for that form the manual.
Does Swift has a defined initialization order of properties? If it does, what is the rule, and where can I find the rule?
This is due to the fact that you're using a Closure (a Function is just a special case of Closure that is unnamed) to initialize the _con1 property with a default value.
From the Apple provided iBook:
If you use a closure to initialize a property, remember that the rest
of the instance has not yet been initialized at the point that the
closure is executed. This means that you cannot access any other
property values from within your closure, even if those properties
have default values. You also cannot use the implicit self property,
or call any of the instance’s methods.
Even though the note above refers specifically to closures, it seems that trying to set the default value for a property to be that of another property directly also does not work.