7
3

More than 3 years have passed since last update.

IBOutletのwillSetで他のIBOutletを参照してはいけない(Swift)

Last updated at Posted at 2020-06-18

名前と名字のラベルからフルネームのラベルのテキストをセットする処理を考えます。
(わかりやすさのために .text を強制アンラップしています)

×
import UIKit

final class FooViewController: UIViewController {
    @IBOutlet private weak var firstNameLabel: UILabel!
    @IBOutlet private weak var familyNameLabel: UILabel!
    @IBOutlet private weak var fullNameLabel: UILabel! {
        willSet {
            newValue.text = "\(firstNameLabel.text!) \(fullNameLabel.text!)"
        }
    }
}

このように記述した場合、以下のエラーが発生することがあります。

Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file /.../FooViewController.swift, line 8

firstNameLabel または familyNameLabel の初期化前に、 fullNameLabelwillSet 内の処理が実行されたのが原因です。

IBOutlet の初期化順は、変数名または内部的に持っているIDで決まります。
(変数をリネームしたら初期化順が変わったので間違いないです)
そのため、 IBOutletwillSet 内で、他の IBOutlet を参照する処理を実行するのはやめましょう。
私が試したときは didSet だと実行時エラーにならなかったのですが、同様に避けるべきだと思います。

他の IBOutlet を参照したい場合、素直に viewDidLoad() で実行するのがベターです。

import UIKit

final class FooViewController: UIViewController {
    @IBOutlet private weak var firstNameLabel: UILabel!
    @IBOutlet private weak var familyNameLabel: UILabel!
    @IBOutlet private weak var fullNameLabel: UILabel!

    override func viewDidLoad() {
        configureFullNameLabel()
    }

    private func configureFullNameLabel() {
        fullNameLabel.text = "\(firstNameLabel.text!) \(fullNameLabel.text!)"
    }
}

私は delegatedataSourcewillSet 内で紐付けがちですが、それもこれからはやめようと思います。

最後に、もし IBOutlet の初期化順を決める方法があれば教えてほしいです笑

7
3
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
7
3