Is it possible to allow didSet to be called during initialization in Swift?

我是研究僧i 提交于 2019-11-26 19:29:40

Create an own set-Method and use it within your init-Method:

class SomeClass {
    var someProperty: AnyObject! {
        didSet {
            //do some Stuff
        }
    }

    init(someProperty: AnyObject) {
        setSomeProperty(someProperty)
    }

    func setSomeProperty(newValue:AnyObject) {
        self.someProperty = newValue
    }
}
Brian Westphal

If you use defer inside of an initializer, for updating any optional properties or further updating non-optional properties that you've already initialized and after you've called any super.init() methods, then your willSet, didSet, etc. will be called. I find this to be more convenient than implementing separate methods that you have to keep track of calling in the right places.

For example:

public class MyNewType: NSObject {

    public var myRequiredField:Int

    public var myOptionalField:Float? {
        willSet {
            if let newValue = newValue {
                print("I'm going to change to \(newValue)")
            }
        }
        didSet {
            if let myOptionalField = self.myOptionalField {
                print("Now I'm \(myOptionalField)")
            }
        }
    }

    override public init() {
        self.myRequiredField = 1

        super.init()

        // Non-defered
        self.myOptionalField = 6.28

        // Defered
        defer {
            self.myOptionalField = 3.14
        }
    }
}

Will yield:

I'm going to change to 3.14
Now I'm 3.14

As a variation of Oliver's answer, you could wrap the lines in a closure. Eg:

class Classy {

    var foo: Int! { didSet { doStuff() } }

    init( foo: Int ) {
        // closure invokes didSet
        ({ self.foo = foo })()
    }

}

Edit: Brian Westphal's answer is nicer imho. The nice thing about his is that it hints at the intent.

Carmine Cuofano

I had the same problem and this works for me

class SomeClass {
    var someProperty: AnyObject {
        didSet {
            doStuff()
        }
    }

    init(someProperty: AnyObject) {
        defer { self.someProperty = someProperty }
    }

    func doStuff() {
        // do stuff now that someProperty is set
    }
}

This works if you do this in a subclass

class Base {

  var someProperty: AnyObject {
    didSet {
      doStuff()
    }
  }

  required init() {
    someProperty = "hello"
  }

  func doStuff() {
    print(someProperty)
  }
}

class SomeClass: Base {

  required init() {
    super.init()

    someProperty = "hello"
  }
}

let a = Base()
let b = SomeClass()

In a example, didSet is not triggered. But in b example, didSet is triggered, because it is in the subclass. It has to do something with what initialization context really means, in this case the superclass did care about that

Snowman

While this isn't a solution, an alternative way of going about it would be using a class constructor:

class SomeClass {
    var someProperty: AnyObject {
        didSet {
            // do stuff
        }
    }

    class func createInstance(someProperty: AnyObject) -> SomeClass {
        let instance = SomeClass() 
        instance.someProperty = someProperty
        return instance
    }  
}
Cœur

In the particular case where you want to invoke willSet or didSet inside init for a property available in your superclass, you can simply assign your super property directly:

override init(frame: CGRect) {
    super.init(frame: frame)
    // this will call `willSet` and `didSet`
    someProperty = super.someProperty
}

Note that Charlesism solution with a closure would always work too in that case. So my solution is just an alternative.

You can solve it in obj-с way:

class SomeClass {
    private var _someProperty: AnyObject!
    var someProperty: AnyObject{
        get{
            return _someProperty
        }
        set{
            _someProperty = newValue
            doStuff()
        }
    }
    init(someProperty: AnyObject) {
        self.someProperty = someProperty
        doStuff()
    }

    func doStuff() {
        // do stuff now that someProperty is set
    }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!