Swift weakプロパティを持つUIViewControllerを再利用する時は注意しよう。という話し。
概要
Storyboardからoutlet接続されたViewを持つUIViewControllerを再利用しようとした時、outlet接続されたプロパティがnilになる時があります。
再利用されるViewController
class ReuseViewController: UIViewController{ @IBOutlet weak var myView: UIView! .... }
再利用を行うViewController
class ViewController: UIViewController{ var cacheViewController: ReuseViewController? override func viewDidLoad() { super.viewDidLoad() self.cacheViewController = storyboard?.instantiateViewController(withIdentifier: "ReuseViewController") as! ReuseViewController } func presentCacheViewController(){ if let vc = self.cacheViewController { present(self.cacheViewController, animated: true, completion: nil) } } }
上記のように一度生成したViewControllerを保管しておき、再度利用するようなケース、例えばcontainerViewなんかでは使うケースがあるんじゃないかな。
この時、weak自身には参照はカウントを持たないのでARCで破棄されているケースがある。当然、中の処理で参照していたりするとクラッシュしたりViewが表示されないといったことになるので注意。
対応策
- weakをなくし強参照とする。この場合、循環参照に注意。
- または、weak制約のまま参照を持つようにする
class ViewController: UIViewController{ var cacheViewController: ReuseViewController? var cacheView:UIView? override func viewDidLoad() { super.viewDidLoad() self.cacheViewController = storyboard?.instantiateViewController(withIdentifier: "ReuseViewController") as! ReuseViewController self.cacheView = self.cacheViewController.myView } .... }
これで理屈としては消えないはず。
また、以下のようなことをしても
if myView == nil { myView = UIView() }
weak参照の場合、参照を持たないインスタンスを代入しても、代入時点でインスタンスが破棄されるので解決策とはならない。
普段、脳死でweakをつけるので変わったことをするとハマった話し。
リンク
リンク