Можно ли Разрешить вызов didSet во время инициализации в Swift?
вопрос
документы Apple указать, что:
наблюдатели willSet и didSet не вызываются при первой инициализации свойства. Они вызываются только тогда, когда значение свойства задано вне контекста инициализации.
можно ли заставить их вызываться во время инициализации?
Почему?
допустим, у меня есть этот класс
class SomeClass {
var someProperty: AnyObject {
didSet {
doStuff()
}
}
init(someProperty: AnyObject) {
self.someProperty = someProperty
doStuff()
}
func doStuff() {
// do stuff now that someProperty is set
}
}
Я создал метод doStuff
, чтобы сделать вызовы обработки более краткими, но я бы предпочел просто обработать свойство в
8 ответов:
создайте собственный set-метод и используйте его в своем init-методе:
class SomeClass { var someProperty: AnyObject! { didSet { //do some Stuff } } init(someProperty: AnyObject) { setSomeProperty(someProperty) } func setSomeProperty(newValue:AnyObject) { self.someProperty = newValue } }
Если вы используете defer внутри инициализатора, для обновления любых необязательных свойств или дальнейшего обновления необязательных свойств, которые вы уже инициализировали, и после вызова любых методов super init, то ваш willSet, didSet и т. д. будут звать. Я считаю, что это более удобно, чем реализация отдельных методов, которые вы должны отслеживать звонки в нужных местах.
например:
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 } } }
даст:
I'm going to change to 3.14 Now I'm 3.14
как вариант ответа Оливера, вы можете обернуть строки в закрытие. Например:
class Classy { var foo: Int! { didSet { doStuff() } } init( foo: Int ) { // closure invokes didSet ({ self.foo = foo })() } }
Edit: ответ Брайана Вестфаля лучше имхо. Самое приятное в нем то, что он намекает на намерение.
У меня была та же проблема и это работает для меня
class SomeClass { var someProperty: AnyObject { didSet { doStuff() } } init(someProperty: AnyObject) { defer { self.someProperty = someProperty } } func doStuff() { // do stuff now that someProperty is set } }
это работает, если вы делаете это в подклассе
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()
на
a
например,didSet
не срабатывает. Но вb
, например,didSet
срабатывает, потому что в подклассе. Это связано с тем, чтоinitialization context
действительно означает, в этом случаеsuperclass
действительно заботился об этом
хотя это не решение, альтернативный способ сделать это будет использовать конструктор класса:
class SomeClass { var someProperty: AnyObject { didSet { // do stuff } } class func createInstance(someProperty: AnyObject) -> SomeClass { let instance = SomeClass() instance.someProperty = someProperty return instance } }
в частном случае, когда вы хотите вызвать
willSet
илиdidSet
внутриinit
для свойства, доступного в вашем суперклассе, вы можете просто назначить свое супер свойство напрямую:override init(frame: CGRect) { super.init(frame: frame) // this will call `willSet` and `didSet` someProperty = super.someProperty }
отметим, что Charlesism решение с закрытием всегда будет работать в этом случае. Так что мое решение-это просто альтернатива.
вы можете решить его в obj-с так:
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 } }