0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Swift】deinitではwillSet/didSetが呼ばれないというお話

Posted at

結論

init/deinit内でプロパティに代入を行っても、willSet/didSetは呼ばれないので注意しましょう。
ただし、スーパークラスのプロパティのwillSet/didSetは呼ばれるようです。

公式ガイドの注意書き

公式ガイド(The Swift Programming LanguageのProperties)に、以下のような注意書きがあります。

NOTE
The willSet and didSet observers of superclass properties are called when a property is set in a subclass initializer, after the superclass initializer has been called. They are not called while a class is setting its own properties, before the superclass initializer has been called.1

注意
サブクラスのイニシャライザ内で、スーパークラスのイニシャライザが呼ばれた後に、プロパティがセットされたとき、スーパークラスのプロパティのwillSetとdidSetのオブザーバーが呼ばれます。スーパークラスのイニシャライザが呼ばれる以前に、自身のプロパティをセットしている間は呼ばれません。2

なるほど。スーパークラスのプロパティのdidSet/willSetについては、サブクラス内のイニシャライザでスーパクラスのイニシャライザを呼んだ後であれば、機能するということらしいです。
クラス自身で定義したプロパティのdidSet/willSetについては、イニシャライザで呼ばれないのは当然だろということか、記述が見当たりませんでした。

コードで確認

確かにスーパークラスのプロパティのdidSetについては呼ばれました。

class Animal {
    var age: Int {
        didSet {
            print(#function, age, oldValue)
        }
    }
    
    init(age: Int) {
        self.age = age // -> 呼ばれない
    }
}

class Tiger: Animal {
    var family: String {
        didSet {
            print(#function, family, oldValue)
        }
    }
    
    init(age: Int, family: String) {
        self.family = family  // -> 呼ばれない
        super.init(age: age) // -> 呼ばれない
        
        self.age += 0  // -> didSetが呼ばれる!!
        self.family += "" // -> 呼ばれない
    }
    
    deinit {
        print(#function)
        age = 0 // -> 呼ばれる
        family = "" // -> 呼ばれない
    }
}

どういうときに注意すべき?

例えば、Timerをdeinitでinvalidateしたいときに、以下のような書き方をすると呼ばれないので注意しましょう。

class ViewController2: UIViewController {
    var timer: Timer? {
        willSet {
            timer?.invalidate()
        }
    }
    
    deinit {
        timer = nil // nilを代入してもwillSetは呼ばれない!
        // -> timer?.invalidate()
    }
    ...
}

参考

Swiftでdeinit時にメンバ変数(property)のdidSetが呼ばれない気がした
Can I use didSet in deinit?

  1. [The Swift Programming Language - Properties](https://docs.swift.org/swift-book/LanguageGuide/Properties

  2. 太字による強調は訳者による

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?