ARCと__bridgeとバグ退治
とにかく、デバッガがまともにエラーを報告してくれないせいで、原因追及に数日間もかかってしまったのですよ。
・・・いやその。バグを出してしまったのは、自分なんだけどね。
問題となったのは、sharedを用いた某ネットワーククラスの、まさにshared用のメソッド。
+ (MyNetManager *)sharedNetManager { static __strong MyNetManager *__sharedNetManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ __sharedNetManager = [[MyNetManager alloc] init]; }); return __sharedNetManager; }
このshaedメソッド呼び出しの、数回目で強制終了を引き起こしていたのですよ。
この場所を特定するだけでも、ほぼ一日近く時間がかかってしまった。
というのも、あろうことかデバッガーが、試行するたびに異なる場所でのエラーを報告してきたからだ。
それも、この近辺というのならともかく、時によって、「UIButtonのターゲットが見つかりません」だの、「NSObjectに変なメッセージ送ってます」だの、もう、あり得ないエラーが目白押し。
そういったゴミのようなエラー情報の山から、数十回の試行錯誤を経て、ようやくたどり着いたのが、ここ。
だが、プログラムコード自体には、どう見てもエラーらしきコードは無い。
そこで、さらに原因を追求したところ、どうやら__sharedNetManagerのインスタンスが、どこかのタイミングで解放されてしまっているのが原因らしい、ということが分かった。
・・・が。
今回は、ARCを使用している。
・・・つまり。
自分ではreleaseしていないわけで。
とどのつまり、「ARCがどっかで解放してしまっている原因を突き止めろ」というミッションなわけで。
・・・・・・チョーン (;o;)
ええ、もう涙目ですよ。
で、延々と調べていったところ、ようやく原因を見つけました。
どこかというと、なんと、Reachabilityを調べる関数のコールバックのなか。
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) { if ([(__bridge NSObject *)info isKindOfClass:[MyNetManager class]]) { MyNetManager *nmgr = (__bridge_transfer MyNetManager *)info; [nmgr updateReachabilityStatWithFlags:flags]; } }
・・・そう、このなかでMyNetManagerインスタンスの確保にあたり、うっかり__bridge_transferを使用していたせい。
てか、なぜ__bridge_transferになっているかな、こいつ。ばたばた打ち込んでいたせいで、オートコレクトを間違えたんだろうか。
ともあれ、ここの__bridge_transferを__bridgeに変更することで、ようやく原因不明のバグの嵐から解放されたのでした。
・・・・・・・・・・・。
あー。もー。ARCでメモリバグが出ると、ここまでマンドクサイとは思わなかった。
__bridgeを使う際には、十分注意しましょう。