名前と名字のラベルからフルネームのラベルのテキストをセットする処理を考えます。
(わかりやすさのために .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
の初期化前に、 fullNameLabel
の willSet
内の処理が実行されたのが原因です。
IBOutlet
の初期化順は、変数名または内部的に持っているIDで決まります。
(変数をリネームしたら初期化順が変わったので間違いないです)
そのため、 IBOutlet
の willSet
内で、他の 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!)"
}
}
私は delegate
や dataSource
を willSet
内で紐付けがちですが、それもこれからはやめようと思います。
最後に、もし IBOutlet
の初期化順を決める方法があれば教えてほしいです笑