What Makes a Property a Computed Property in Swift

What makes a property a computed property in Swift

First, this is about variables, not properties. Any variable can be a computed variable. A property is just one way to use a variable.

I think on the whole you are making a big mistake in putting a stored variable with setter observers side by side with a computed variable. They are unrelated!

Think of a computed variable as something that looks and acts like a variable when you use it — you get and (maybe) set it — but is in fact a function (or a pair of functions). It is just a compact way of calling a function. That's all it is.

A stored variable with observers, on the other hand, is just a stored variable that also has some observers.


Okay, on to your questions:

  1. I wonder what makes a property a computed property? Is is correct that as long as the property has a getter and return it is a computed property?

Yes. It's a computed variable because you declared it using the syntax that makes it a computed variable (with the curly braces).


  1. Are all my understandings (a, b & c) correct? If not would be nice of you to point out

Yes. I think your "c" is quite insightful: a computed variable does not need a setter observer because it has (gasp!) a setter!


  1. Why is it not allowed to initialize an computed property? (Please see the figure below) And when I do so the compiler gives out the warning Cannot call value of none-function type "int" What's the meaning of this error?

There is no sense in which a computed variable "has" a value — it is computed! it's just some functions! — so it makes no sense to assign it an "initial" value.

Computed Property

A computed property calculates its value depending on other values (in the object).

An efficient solution is a switch statement

struct Colour {
var red: Int
var green: Int
var blue: Int
var colourName: String
var chosenColour: String {
switch (red, green, blue) {
case (255, 255, 255): return "White"
case (0, 0, 0): return "Black"
case (255, 0, 0): return "Red"
case (0, 255, 0): return "Green"
case (0, 0, 255): return "Blue"
default: return "Mixed Colour"
}
}
}

What is the difference between the following 3 declarations?

1.

var title: UILabel {
let label = UILabel()
textLabel.font = .systemFontOfSize(13)
return label
}

It is a read only computed property. Computed properties cannot be let. These are calculated using other stored/computed properties. So they don't have any backing store of their own. Hence, computed properties are always declared as var.

2.

let title: UILabel = {
let label = UILabel()
textLabel.font = .systemFontOfSize(13)
return label
}()

It is a stored property. This is assigned a closure that returns a UILabel object. This closure is executed during the instantiation process of the object and the returned UILabel object is assigned to title.

3.

lazy var title: UILabel = {
let label = UILabel()
textLabel.font = .systemFontOfSize(13)
return label
}()

It is a lazy stored property. It is also assigned a closure that returns a UILabel object. But this closure is not executed during the instantiation process. It is executed whenever this property is first used. After the execution of the closure, the UILabel object returned is assigned to title.

difference between a computed property and setting a function to a variable in Swift

The code in the computed property gets executed every time you reference that variable. The code in the property initialized by a closure is only executed once, during initialization.

Computed property does not require storage allocation

Computed properties are much like functions that take no arguments and return a value. For the lifetime of the execution of a computed property, some memory will temporarily be allocated on the stack, to store the local variables of the computed property.

In addition to this, the instructions of the computed property have to be stored somewhere in your compiled program. Luckily, you only need one copy of the definition, which can be used for all instances.

The important point is that there is no per-instance memory required.

Swift: why lazy, computed property, and property observer can not be let

Lazy properties : You must always declare a lazy property as a variable (with the var keyword), because its initial value might not be retrieved until after instance initialization completes. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.

computed property : whereas computed properties calculate (rather than store) a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.

property observer : property observers is to monitor changes in a property’s value, if you define it let then how you can monitor changes because let is one type of constant which you can not change after init.

Difference between computed property and property set with closure

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.

Swift binding to a computed property

Make it a @Published property and update it when project is changed

class MyViewModel: ObservableObject {
@Published var project: Project {
didSet {
isProjectValid = project.name != "" && project.duration > 0
}
}

@Published var isProjectValid: Bool

//...
}


Related Topics



Leave a reply



Submit