William Hu
William Hu

Reputation: 16159

Swift can lazy and didSet set together

I have a property

public lazy var points: [(CGFloat,CGFloat,CGFloat)] = {
        var pointsT = [(CGFloat,CGFloat,CGFloat)]()
        let height = 100.0
        for _ in 1...10 {
            pointsT.append((someValue,someValue,100.0))
        }
        return pointsT
    }()

And i want to add a didSet method, is it possible?

Upvotes: 26

Views: 9618

Answers (4)

Hayk Ghazaryan
Hayk Ghazaryan

Reputation: 61

Yes, Started by version Swift 5.3 Property observers can now be attached to lazy properties.

class C {
  lazy var property: Int = 0 {
    willSet { print("willSet called!") } // Okay
    didSet { print("didSet called!") } // Okay
  }
}

or

class C {
  lazy var property: Int = { return 0 }() {
    willSet { print("willSet called!") } // Okay
    didSet { print("didSet called!") } // Okay
  }
}

Please take a look at the links below for more:

  1. https://www.swiftbysundell.com/tips/lazy-property-observers/
  2. https://github.com/apple/swift/blob/main/CHANGELOG.md

Upvotes: 6

Joseph Lord
Joseph Lord

Reputation: 6504

The short answer is as other have said is "no" but there is a way to get the effect using a private lazy var and computed var.

private lazy var _username: String? = {
    return loadUsername()
}()
var username: String? {
    set {
        // Do willSet stuff in here
        if newValue != _username {
            saveUsername(newValue)
        }
        // Don't forget to set the internal variable
        _username = newValue
        // Do didSet stuff here
        // ...
    }
    get {
        return _username
    }
}

Upvotes: 9

luk2302
luk2302

Reputation: 57134

No

points is a constant, you cannot set anything to it. The only difference to a let constant is that it is (potentially) initialized later.

This answer provides a little more information as to why you use var instead of let in the lazy case.

Edit: to make the answer not look to empty Take a look at this blog post where the author raises a few valid points regarding why observing lazy vars might not yet be supported. What should oldValue be in the observer? nil? That would not be a good idea in your non-optional case.

Upvotes: 3

dfrib
dfrib

Reputation: 73186

Short answer: no.

Try out this simple example in some class or method of yours:

lazy var myLazyVar: Int = {
    return 1
} () {
    willSet {
        print("About to set lazy var!")
    }
}

This gives you the following compile time error:

Lazy properties may not have observers.


With regard to the let statement in the other answer: lazy variable are not necessary just "let constants with delayed initialisation". Consider the following example:

struct MyStruct {
    var myInt = 1

    mutating func increaseMyInt() {
        myInt += 1
    }

    lazy var myLazyVar: Int = {
        return self.myInt
    } ()
}

var a = MyStruct()
print(a.myLazyVar) // 1
a.increaseMyInt()
print(a.myLazyVar) // 1: "initialiser" only called once, OK
a.myLazyVar += 1
print(a.myLazyVar) // 2: however we can still mutate the value
                   //    directly if we so wishes

Upvotes: 27

Related Questions