NSCalendar由来のEXC_BAD_ACCESSに苦労した

先日iOS 10用にリニューアルしたアプリを公開したところ、「クラッシュするよ」との指摘をもらいました。詳しく聞いてみると、使っている機種はiPad Retina(4th Generation)とのこと。
開発中にiPad mini 2(retina)の実機とiPad Air2/Proのシミュレータで動作確認はしていたので、iPad Retinaでだけ動かないのは意外でした。
iPad Retinaのシミュレータで動かしてみると、確かに特定の画面でクラッシュします。エラー内容は悪名高き「EXC_BAD_ACCESS」。これだけではさっぱりわからないので、特定のために設定をします。
まず、Zombie Objects。設定の仕方が、Xcode 7あたりから大きく変わっていて、古い情報(「Arguments」タブの「Environment Variables」に「NSZombieEnabled = enable」を追加)を見てしまうとうまく動作しません。Xcode 8.2では、Edit Scheme… から下記のチェックボックスで指定します。
DuelScoreViewController_m
これを設定したところエラーメッセージが変化しました。

2017-01-08 11:58:14.444 DuelCalculator[64620:2819605] *** -[_NSCopyOnWriteCalendarWrapper release]: message sent to deallocated instance 0x79673240

既に存在しないオブジェクトを更にreleaseしようとしている、くらいのことはわかりました。しかし、オブジェクトのポインタのアドレスしかわからず、具体的にソースコードのどの部分かも表示してくれません・・
こちらの方法で、目ぼしいところのオブジェクトのアドレスを表示してみたりしましたが、やはりはっきりせず。

NSLogでポインタのアドレスを出力する書式があるのを知りました。 NSObject* obj = init]; NSLog(@"%p", obj); これで「0x681d640」などと、頭に0xをつけて16進数で出力してくれます。 今までは NSLog(@"%08X", (int)obj); などとやっていましたが...
ということで、更に詳しい情報を得るために、Instrumentsを使ってみました。(shell malloc_history というのも古いXcode用の情報です)
ここまで来てやっと具体的なメソッドがわかったので、修正を行います。
しかし今回のバグは、iPad Retinaだけに発生するということで、なかなか修正方法がわかりません。修正しつついろいろググっているうちに、下記の情報にたどり着きました。
I have created (NSCalendar* cal;) when I copy it to use (NSCalendar* calendar = ;) this is error Error : message sent to deallocated instance How Can...
確かに、使っているコードに下記がありました。

NSCalendar *cal = [[NSCalendar currentCalendar] autorelease];

これがなぜiPad Retinaでだけ動作しないのかわかりませんが、恐らくアーキテクチャが32bitのためではないかと推測されます。これを、下記に直したところ、無事動きました。

NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];

今後はiPad Retinaのシミュレータでも一通り動かさないといけないですね。。
そして思いたち、他の32bitアーキテクチャ(iPhone 4s)のシミュレータで確認してみたところ、やっぱり落ちました。iPhone 4s/5/5cなどをお使いの方すみません。。Appleには既に審査依頼したので、そのうち更新されると思います。
・追記
カレンダーのインスタンス化の仕方は気をつけないといけないようですね。
http://qiita.com/moriteru/items/effb1b8c4affb6d33c1a

スポンサーリンク

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

スポンサーリンク