问题

苹果的文件明确指出:

当属性第一次初始化时,不会调用willSet和didSet观察器。只有当属性的值在初始化上下文之外设置时才会调用它们。

是否有可能在初始化期间强制调用这些?

Why?

假设我有这样一个类

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

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

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

我创建了方法doStuff,以使处理调用更简洁,但我宁愿只处理didSet函数中的属性。有没有办法在初始化期间强制调用这个?

更新

我决定删除类的方便初始化器,并强制您在初始化后设置属性。这让我知道didSet总是会被调用。我还没有决定这是否是更好的整体,但它很适合我的情况。


当前回答

虽然这不是一个解决方案,但另一种方法是使用类构造函数:

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

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

其他回答

在特定的情况下,你想在init中调用willSet或didSet来获取父类中可用的属性,你可以简单地直接分配你的父属性:

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

注意,带闭包的Charlesism解决方案在这种情况下也总是有效的。所以我的解只是一种选择。

虽然这不是一个解决方案,但另一种方法是使用类构造函数:

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

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

我也有同样的问题,这个方法对我很有效

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

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

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

作为Oliver回答的一种变体,您可以将这些行包装成闭包。例如:

class Classy {

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

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

}

编辑:Brian Westphal的回答更好。这句话的好处是暗示了他的意图。

如果你在子类中这样做,这是可行的

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()

在本例中,没有触发didSet。但是在b的例子中,didSet被触发了,因为它在子类中。它必须处理初始化上下文的真正含义,在这种情况下,超类确实关心这个