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)
Related
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.
I was trying to do something like this (it is a contrived example for demonstration purposes only):
class Test {
let hello = "hello"
let world = "world"
let phrase: String {
return self.hello + self.world
}
}
but you can't use let for computed properties in Swift. Is there a way to do this without having to write an init() method? Thanks!
The reason let doesn't work on a read-only calculated property is because it's used to state that the property's actual value will never change after being set – not that the property is read-only. As the Apple docs say (emphasis mine):
You must declare computed properties — including read-only computed
properties — as variable properties with the var keyword, because their
value is not fixed. The let keyword is only used for constant
properties, to indicate that their values cannot be changed once they
are set as part of instance initialization.
You therefore need to use var in order to reflect the fact that a calculated property's value could change at any time, as you're creating it on the fly when accessing it. Although in your code, this can't happen – as your hello and world properties are let constants themselves. However, Swift is unable to infer this, so you still have to use var.
For example:
class Test {
let hello = "hello"
let world = "world"
var phrase: String {
return self.hello + self.world
}
}
(This doesn't change the readability of the property – as because you haven't provided it with a setter, it's still read-only)
However in your case, you might want to consider using a lazy property instead, as your hello and world properties are constants. A lazy property is created when it's first accessed, and keeps its value for the rest of its lifetime – meaning you won't have to keep on concatenating two constants together every time you access it.
For example:
class Test {
let hello = "hello"
let world = "world"
lazy var phrase: String = {
return self.hello + self.world
}()
}
Another characteristic of let properties is that their value should always be known before initialisation. Because the value of a lazy property might not be known before then, you also need to define it as a var.
If you're still adamant on wanting a let property for this, then as far as I can see, you have two options.
The first is the neatest (although you've said you don't want to do it) – you can assign your phrase property in the initialiser. As long as you do this before the super.init call, you don't have to deal with optionals. For example:
class Test {
let hello = "hello"
let world = "world"
let phrase: String
init() {
phrase = hello+world
}
}
You simply cannot do it inline, as self at that scope refers to the static class, not an instance of the class. Therefore you cannot access the instance members, and have to use init() or a lazy/calculated property.
The second option is pretty hacky – you can mirror your hello and world properties at class level, so you can therefore access them inline in your phrase declaration. For example:
class Test {
static let hello = "hello"
static let world = "world"
// for some reason, Swift has trouble inferring the type
// of the static mirrored versions of these properties
let hello:String = Test.hello
let world:String = Test.world
let phrase = hello+world
}
If you don't actually need your hello or world properties as instance properties, then you can just make them static – which will solve your problem.
Yes to make it work as computed properties, replace let to var.
Like,
class Test {
let hello = "hello"
let world = "world"
var phrase: String {
return self.hello + self.world
}
}
This way you can use it without init()
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
I am new to Swift and am confused with this type of syntax. I know when you add () to the end of something you initialize it. I am still confused what this means though! I am adding code below.
Please help clarify what parenthesis at the end of this means! Thank you!
Also what does it mean to have all that code after the equal sign in this case? ( I know how to create a variable and add a String,Int or something like that to it).
I am just confused a bit wth this code.
Thanks for being understanding to a beginner!
var viewController: ViewController = {
return self.instantiateViewControllerWithIdentifier("Play") as ViewController
}()
EDIT 1 -
var statusBarStyle: UIStatusBarStyle = .Default {
didSet{
setNeedsStatusBarAppearanceUpdate()
}
}
{} declares a closure, which is anonymous function. Everything between { and } is a function body. Since closure defined in provided code does not have arguments it can be executed as regular function by (). { .. }() is just defining and immediately executing of anonymous function.
In a body of a function there is a call of instantiateViewControllerWithIdentifier("Play") which returns AnyObject. As viewController variable (var) expected to ba a type of ViewController, we cast AnyObject result of instantiateViewControllerWithIdentifier as ViewController
As for statusBarStyle, UIStatusBarStyle is an enum. .Default is one of enum's cases. It can be written alternatively as var statusBarStyle = UIStatusBarStyle.Default. The code that goes in the { ... } is a way to declare getter and setter behavior. In this particular case there is only one behavior didSet defined, which means as soon as value of UIStatusBarStyle updated (which is possible, as it is var), call function setNeedsStatusBarAppearanceUpdate. There are other getters & setters keywords that you may read about in Swift Book — https://itunes.apple.com/us/book/swift-programming-language/id881256329 such as get, set, willSet.
As Nikita said its instantly calling the anonymous function you declared. This is really useful as it allows you to add logic when initialising a var or let.
Since the function takes no arguments, it makes it harder to see at first that it actually is a function. An example with an argument makes this concept a lot clearer.
let oneMore: Int = { (num: Int) in num + 1 }(5) //oneMore = 6
We are creating a function that takes one Int argument num and implicitly returns an Int (the compiler knows this because of the type annotation on oneMore. By following the closure with (5) we are calling the anonymous function with the value of 5.
Hopefully this example makes it more clear what happening. Note for an anonymous function in the context we would never need to provide argument since it will only ever be called once with the arguments following it, so we can just include the argument within the function body.
let oneMore: Int = { 5 + 1 }()
In the second example the braces are allowing you to include property observers to the variable. an example of a property observer is didSet which is called each time after you assign a value to the variable. more info can be found in apples docs here.
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.