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
を作成しましたが、didSet
関数内のプロパティを処理するだけです。初期化中にこれを強制的に呼び出す方法はありますか?
クラスの便利な初期化子を削除して、初期化後にプロパティを設定するように強制することにしました。これにより、didSet
が常に呼び出されることを知ることができます。全体的にこれが良いかどうかは決めていませんが、私の状況によく合っています。
独自の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
}
}
初期化子内で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
Oliverの回答のバリエーションとして、クロージャーでラインをラップすることができます。例えば:
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
はそれを気にしました
スーパークラスで使用可能なプロパティのwillSet
内でdidSet
またはinit
を呼び出す特定のケースでは、スーパープロパティを直接割り当てることができます。
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
}
}