職業プログラマの休日出勤

職業プログラマによる日曜自宅プログラミングや思考実験の成果たち。リアル休日出勤が発生すると更新が滞りがちになる。記事の内容は個人の意見であり、所属している(いた)組織の意見ではない。

アクセサリの使い回し

僕が身だしなみに気を付け始めた…と思ったら大間違いです。
今夜は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 は打ってみました(が、見てくれるかどうか不安…)。

再現環境情報

  • iOS SDK 6 でビルド & iOS6で動かす ⇒ 無限ループ
  • iOS SDK 6 でビルド & iOS5で動かす ⇒ 正常に動作
  • iOS SDK 5 でビルド & iOS6で動かす ⇒ 正常に動作
  • iOS SDK 5 でビルド & iOS5で動かす ⇒ 正常に動作

開発環境

追記@2012.10.28

バグ報告に対する回答をAppleさんから頂きました。
「Viewは使い回すんじゃなくて、毎回生成するのが正しい使い方なんだ。そういう風に作ってね。」
と。
要はバグじゃなくて仕様だよ、という話ですね。
仕様とは言っても、無限ループに突入されたら原因追及は難しくなってしまうので、開発するときは気を付けておきたいところです。