僕が身だしなみに気を付け始めた…と思ったら大間違いです。
今夜はiOSのお話。
この記事の問題で、先日の祝日 "Labour Day" 丸一日を潰してしまったので、悔しさを込めて記事にします。
現象
UINavigationBarとUITableViewを組み合わせたアプリの開発中に出くわした現象です。
表示させようとしたViewControllerの viewWillAppear の処理が正常に終了したあと、 viewDidAppear が呼ばれないまま、表示が固まってしまいました。
何秒経っても動く気配がありません。iOSからアプリが殺される気配もありません(珍しい…)。
Simulatorでも実機でも同じ症状。Simulatorでこれをやると、MacのCPU使用率が上がります(コア1個を占有⇒無限ループの可能性大)。
調査
まずは、viewWillAppearが終わってviewDidAppearが呼ばれるまでの間に何が起きているのか調査すべく、デバッガでステップ実行してみました。そこで、TableViewDataSourceのメソッドが一通り呼ばれた後にCoreAnimation関連?のところで無限ループしていることを突き止めました。しかし、それ以上は何も手がかり無し(アセンブラ読めないし…)。
次。特定のTableViewで常に発生し、他のTableViewでは全く発生しないことから、TableView or ViewController が何かの条件を満たすと発生するんだろう、と推測を立てました。
発生していたTableViewに特徴的な要素は
- Grouped TableView のセクションヘッダ/フッタを使用していた
くらいだったので、試しに消してみたりもしたけど、何も変わらず。
困り果てながら試行錯誤すること数時間…
結論
どうやら、一つの UIView インスタンスを複数の UITableViewCell の accessoryView に指定すると、無限ループに陥るようです。
回避策
accessoryView をセットする時に、UIViewのインスタンスをコピーしてセットする(もしくは毎回インスタンス作成する)しか無さそうです。
「アクセサリは使い回ししちゃダメよ」ということですね。
とりあえず BugReport は打ってみました(が、見てくれるかどうか不安…)。
再現環境情報
追記@2012.10.28
バグ報告に対する回答をAppleさんから頂きました。
「Viewは使い回すんじゃなくて、毎回生成するのが正しい使い方なんだ。そういう風に作ってね。」
と。
要はバグじゃなくて仕様だよ、という話ですね。
仕様とは言っても、無限ループに突入されたら原因追及は難しくなってしまうので、開発するときは気を付けておきたいところです。