I was wondering if this behavior in the swift language is documented anywhere. I haven't been able to find it in the official documentation. It is best expressed in code:
var testBacking = CGPoint(x: 3, y: 5)
var testPoint:CGPoint {
get {
print("getter called")
return testBacking
} set {
print("setter called with newValue = \(newValue)")
testBacking = newValue
}
}
testPoint.x = 10 // getter called
// setter called with newValue = (10.0, 5.0)
As you can see, I am only setting the x component of the computed structure testPoint, and in doing so, swift automatically calls the getter first and pulls out the y component and builds a complete structure that it then passes to the setter as newValue. This seems like appropriate behavior. My question is: Where is this behavior documented? Have I missed it, or is it simply not mentioned?
The way to understand this is to consider a similar but simpler case without your extra complications. Let's just talk about this:
struct S {
var name = "matt"
}
var s = S()
s.name = "mogelbuster"
How does that work? What happens when we set s.name? First, pull out the current value of s; then, we set its name property; then, we set the value of s to this new struct. (You can easily confirm that last part by putting a setter observer on s.)
Setting a struct's property by way of a reference, then involves getting the reference's value (the struct), setting the property, and setting the reference's value with the new struct. That's because a struct is a value type. It cannot be mutated in place, so setting a property by way of a reference to a struct involves setting into the reference.
What you are doing with testPoint is merely a computed-variable version of the same process. The mere act of speaking of testPoint.x means that we must get testBacking, to find out what it is. Thus, the getter is called. Then you set into testPoint.x, thus calling the setter to write the new value back into testBacking.
Note that the same thing would not be true if we were working with a class. Here's a variation on your original example:
class PointHolder {
var point = CGPoint(x:3, y:5)
var x : CGFloat {
get { return point.x }
set { point.x = newValue }
}
}
var testBacking = PointHolder()
var testPoint:PointHolder {
get {
print("getter called")
return testBacking
} set {
print("setter called with newValue = \(newValue)")
testBacking = newValue
}
}
testPoint.x = 10 // getter called, but _not_ setter
In the last line, the testPoint setter is not called — because a class instance is a reference type and is mutable in place. testBacking is changed without setting, because what we got from testBacking when we said testPoint.x, and the getter was called, is a reference; a change to this changes the thing testBacking points to without setting into it.
Hello my problem is simple I have to constantly check whether the value of a bool is true or false, what I have tried so far is to use the:
override func update(_ currentTime: TimeInterval)
function in swift and it is way to fast and once it checks the values it will constantly repeat the action even though I only wish for it to perform the action only once, so basically what I'm saying is that all I want to do is to check whether the bool value is true or false once and then stop checking until it changes again. Please help, thank you.
Property Observers
You can use Property Observers in Swift to accomplish what you need... Here is what docs says about these:
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.
There are willSet and didSet property observers:
willSet is called just before the value is stored.
didSet is called immediately after the new value is stored.
To solve your problem, you could do something like this:
var myProperty:Int = 0 {
willSet {
print("About to set myProperty, newValue = \(newValue)")
}
didSet{
print("myProperty is now \(myProperty). Previous value was \(oldValue)")
}
}
You can implement either one or both of property observers on your property.
Getters and Setters
As an alternative, You can use getters and setters on a stored property to solve your problem:
private var priv_property:Int = 0
var myProperty:Int{
get {
return priv_property
}
set {
priv_property = newValue
}
}
Computed properties do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.
You should use observers or callbacks. Read comments below and see #Whirlwind's answer. The solution below is not really recommended since it would be inefficient and might complicate your code. But if you wanted or needed to do it in the update(), here's how I'd do it:
// Assume stored property
// It might be an API call and so on
var boolToWatch = false
var lastValueOfWatchedBool: Bool?
var lastCheck: TimeInterval = 0
let checkInterval = 1.0 // check every second
override func update(_ currentTime: TimeInterval) {
// In case boolToWatch is an expensive API call might be good to
// check less frequently
if currentTime - lastCheck > checkInterval {
lastCheck = currentTime
// Check for the initial case
if lastValueOfWatchedBool == nil {
lastValueOfWatchedBool = boolToWatch
}
// Detect change
if boolToWatch != lastValueOfWatchedBool {
lastValueOfWatchedBool = boolToWatch
// Do what you need to do when the value changed here
print("I feel different!")
}
}
}
I have a superclass where a vector is being created as a member variable.
class GameScene: SKScene, SKPhysicsContactDelegate {
var floatingBlockPositions: [CGPoint] = [CGPointMake(130.0, 70.0)]
}
I am overriding it in a subclass like so:
class StreetFight: GameScene {
override var floatingBlockPositions: [CGPoint] {
get {
return [CGPointMake(400.0, 70.0), CGPointMake(250.0, 95.0)]
}
set (newValue) {
newValue
}
}
}
I have a class method that mutates it to set another parameter.
temp = 0
for _ in floatingBlockPositions {
floatingBlockPositions[temp].y = floatingBlockPositions[temp].y + positionsForFirstBlock.y + (groundBlockSize.height / 2)
let aerialBlock = SKSpriteNode(imageNamed: "aerialBlock")
aerialBlock.position = floatingBlockPositions[temp]
temp++
}
After debugging, I see that the setter in the subclass is being called, but it is not being set properly because the equals operator in the function is trying to set only one part of one of the CGPoints in the vector, which the setter is not set up to handle, no pun intended. How can I write the setter in the subclass so it recognizes what part of floatingBlockPositions needs to be set and sets it. If possible, should I overload the method, or is there a better way to do it?
You've changed floatingBlockPositions from a stored property to a computed variable (because it has a get). Therefore, you cannot store a new value for it. However, you can create a separate private var and set that, and then in get, if that is set, return that new value.
I have two properties in my class. See this terrible example:
var length
var doubleLength
How do I initialize doubleLength based on length?
init() {
self.length = ...
self.doubleLength = self.length * 2
super.init()
}
I get an error that I can't access self before I call super.init(). Well I need to set all my variables before I can even call super.init() so what am I supposed to do?
if self.doubleLength is always supposed to be twice self.length (in this example) have you considered just using a computed property?
class MyClass: MySuperClass {
var length: Double
var doubleLength: Double {
return self.length * 2
}
init(len: Double) {
self.length = len
super.init()
}
}
You can temporarily delay the initialization of doubleLength an implicitly unwrapped optional, which will allow to temporarily assign a value to nil and assign it at a later time.
class Something: UICollectionViewLayout {
var doubleLength: Int! = nil
var length: Int {
return 50
}
init() {
super.init()
doubleLength = length * 2
}
}
Anyway, in this specific case I think it would be nicer to make doubleLength a computed property, since it can be always be computed from the value of length. Your class will be like
class Something: UICollectionViewLayout {
var doubleLength: Int {
return length * 2
}
var length: Int {
return 50
}
}
Thanks for your full reproduction, which is:
import UIKit
class Something: UICollectionViewLayout {
var doubleLength: Int
var length: Int {
return 50
}
init() {
doubleLength = length * 2
super.init()
}
}
From this we can see that you're using a getter to return your property. I think this is what's causing the problem. For example, if you just do this:
import UIKit
class Something: UICollectionViewLayout {
var doubleLength: Int
// Simple variable, no code.
var length = 50
init() {
doubleLength = length * 2
super.init()
}
}
...then that works fine.
I believe this is because the Swift compiler is trying to prevent you from doing anything that might mean you use the base class's methods, properties or variables before it's been initialised. I know you're technically not, in your example, but consider how hard it is to trace back and see what's being done from your initialiser. For example, if you were to do:
var length: Int {
// Where "width" is a made-up property of UICollectionViewLayout
return width * 3
}
...then your code would be run from your initialiser and use a property of UICollectionViewLayout before its own init had been called, therefore making it possibly invalid.
So my best guess is that this is the Swift compiler making a blanket ban on calling out to any code outside the subclass initialiser before the super is initialised.
You get exactly the same error if you do this, for example:
class Something: UICollectionViewLayout {
func foo() {
// Do nothing
}
init() {
foo() // error: 'self' used before super.init call
super.init()
}
}
The place I remember this being explained is the "Intermediate Swift" video from WWDC 2014, from slide 191, about 20 minutes in, but I'm guessing it's somewhere in the book, too...
A property that depends on another is bad practice. Just like when you design a database, you avoid calculated fields, when you design classes, you also avoid calculated fields. Instead of having a doubleLength property, you should instead have a getDoubleLength method that returns the length * 2.
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.