是否有可能允许didSet在初始化过程中调用Swift?
题
苹果的文档指出:
当一个属性第一次初始化时,willSet和didSet观察者不会被调用。 只有当属性值设置在初始化上下文之外时,才会调用它们。
在初始化过程中是否可以强制这些被调用?
为什么?
比方说,我有这个class
class SomeClass { var someProperty: AnyObject { didSet { doStuff() } } init(someProperty: AnyObject) { self.someProperty = someProperty doStuff() } func doStuff() { // do stuff now that someProperty is set } }
我创build了方法doStuff
,使处理调用更简洁,但我宁愿只是在didSet
函数内处理属性。 有没有办法强制这个在初始化过程中调用?
更新
我决定删除我的类的方便初始化程序,并强制您在初始化后设置属性。 这让我知道didSet
总是会被调用。 我还没有决定这是否更好,但它适合我的情况。
创build一个自己的set-Method并在init-Method中使用它:
class SomeClass { var someProperty: AnyObject! { didSet { //do some Stuff } } init(someProperty: AnyObject) { setSomeProperty(someProperty) } func setSomeProperty(newValue:AnyObject) { self.someProperty = newValue } }
如果在初始化程序中使用延迟,为了更新任何可选属性或进一步更新已经初始化的非可选属性,并且在调用任何超级初始化方法之后,将调用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 })() } }
编辑:布赖恩韦斯特法尔的答案是更好的恕我直言。 关于他的好处是暗示了他的意图。
我有同样的问题,这对我的作品
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
就是在意这一点
虽然这不是一个解决scheme,但另一种解决方法是使用类构造函数:
class SomeClass { var someProperty: AnyObject { didSet { // do stuff } } class func createInstance(someProperty: AnyObject) -> SomeClass { let instance = SomeClass() instance.someProperty = someProperty return instance } }
在特定的情况下,如果你想在你的超类中可用的属性中调用willSet
或didSet
,你可以直接指定你的超级属性:
override init(frame: CGRect) { super.init(frame: frame) // this will call `willSet` and `didSet` someProperty = super.someProperty }
请注意,具有闭包的查尔斯主义解决scheme在这种情况下总是可以工作的。 所以我的解决scheme只是一个select。
你可以用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 } }