2015-10-25 12 views
7

私は現場の多くのユーザーから報告されたクラッシュするバグをデバッグしようとしています。iOS9.1のdispatch_asyncでSIGABRTをトリガできる原因は何ですか?

2363: BOOL success = [db executeUpdate:@"INSERT INTO table (id, content) VALUES (?, ?)", message.remoteId, message.content]; 
2364: assert(success); 
2365: DebugLog(@"DB Results %d", success); 
2366: 
2367: dispatch_async(dispatch_get_main_queue(), ^{ 
2368:  [self cleanupMethod:args]; 
2369: }); 

確かにそのブロック内のコードがあるが、それは唯一の1行の長だし、そのコードが実行されるように表示されません。

Exception Type: EXC_CRASH (SIGABRT) 
Exception Codes: 0x0000000000000000, 0x0000000000000000 
Exception Note: EXC_CORPSE_NOTIFY 
Triggered by Thread: 8 
OS Version:   iOS 9.1 (13B143) 
Code Type:   ARM (Native) 

0 libsystem_kernel.dylib   0x392ccc84 0x392b8000 + 85124 
1 libsystem_pthread.dylib   0x39370732 0x3936c000 + 18226 
2 libsystem_c.dylib    0x39264f9a 0x3921a000 + 307098 
3 libsystem_c.dylib    0x39264f2c 0x3921a000 + 306988 
4 libsystem_c.dylib    0x392447ea 0x3921a000 + 174058 
5 MyApp       0x000cb3e0 __69-[MyDataManager myMethod:]_block_invoke (MyDataManager.m:2367) 

ライン2367は単純です:すべては私に同じスタックを表示しますそうでなければ私はcleanupMethodの上にmyMethodを見るでしょう。

編集:dispatch_asyncの直前に、アサートがあることがわかります!私はもともと、このクラッシュが主張に起因すると考えていました。しかし、行番号は一度も一致しませんでした。つまり、アサーションは多くの行が上にあります(行2364ではなく2367)。さらにテストしたところ、アサートがトリガーされた場合、スタックには_block_invoke myMethodの呼び出しの最後に追加されることがあります。

どのようにdispatch_asyncがこの動作を引き起こす可能性がありますか?さらに、libsystem_c.dylibでAppleのコードを象徴する方法はありますか? libsystem_c.dylibの

バイナリイメージ:

0x3921a000 - 0x3927efff libsystem_c.dylib armv7 <0b5d65608e6f38448cd207fbd748d372> /usr/lib/system/libsystem_c.dylib 

注:あなたがする場合は問題のオブジェクトがグローバルシングルトン、私の "データ管理" です。ネットワーク要求を処理し、UIViewController間で共有する必要のある状態を格納します。これは次のようにもともと宣言されています:

+ (MyDataManager *)mainStore { 
    static dispatch_once_t once; 
    static id sharedInstance; 
    dispatch_once(&once, ^{ 
     sharedInstance = [[self alloc] init]; 
    }); 

    return sharedInstance; 
} 

私は私のcleanupMethod:argsメソッドが呼び出されたときに割り当て解除されているオブジェクトの結果を理解...しかし、私はは私のグローバルシングルトンは、常に周りので、常に安全になりと思っていました自分のコードでやり取りする方法で呼び出しますか?私はさらに、今度はグローバルシングルトンであると考えられて以来、保持サイクルについて心配していません。

このコードサンプルは次のとおりですか?

@interface MyDataManager 
@end 

@implementation MyDataManager 

+ (MyDataManager *)mainStore { 
    static dispatch_once_t once; 
    static id sharedInstance; 
    dispatch_once(&once, ^{ 
     sharedInstance = [[self alloc] init]; 
    }); 

    return sharedInstance; 
} 

- (void)myMethod { 
    NSDictionary *args = @{...} 
    ... 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self cleanupMethod:args]; 
    }); 
} 

- (void)cleanupMethod:(id)args { 
    ... 
} 

@end 

@interface MyViewController : UIViewController 
@end 

@implementation MyViewController 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    [[MyDataManager sharedInstance] myMethod]; 
} 

@end 
+0

質問を編集してブロックの内容を含めるか、少なくともMyDataManager.mの2367行の次の行を含めると役立ちます。 –

+0

@rob mayoff完了! – esilver

+1

ブロックがトリガされた時点で 'self'のように見えなくなったようです。 –

答えて

2

問題が割り当て解除したselfを呼び出すときに明らかに、あなたのアプリケーションがクラッシュしselfへの強い参照、であるように見えます。

__weak typeof(self)weakSelf = self; 
dispatch_async(dispatch_get_main_queue(), ^{ 
    [weakSelf cleanupMethod:args]; 
}); 

は、いくつかはあなたが作るために、ここにも__strong typeof(weakSelf)strongSelf = weakSelf;を使用しなければならないと言うでしょう: このコードは、問題を解決する必要がありますself弱い参照を格納しようとしている新たな変数を作るだろう生きselfを保つために、私はここでそれを行うには、ケースselfnilは、ブロックの実行時までになりたくないだろうが、強い参照サイクルを回避するために弱参照への強い参照、 - メッセージnilには完全にあります客観的にはうまくいっているので、何も起こりません。

プラス前ライン

0x000cb3e0 __69-[MyDataManager myMethod:]_block_invoke (MyDataManager.m:2367) 

は間違いなく問題を診断するのに役立つだろう、何が起こるかのスタックトレース。

編集:共有オブジェクトにアクセスする際に、クラスメソッドmainStoreを使用していないようです。多分それが問題です。

+0

1.誰かが強い参照を保持していることが確かでない限り、弱い変数へのメッセージの送信が適切であると思われる理由を説明してください(弱参照はナンセンスです)。 2. myMethodがコールスタック上にありません。これはメッセージ内のブロックです(ほとんどの場合、cleanupMethodを呼び出すブロックです)。 – gnasher729

+0

1.正確にこの状況のた​​めに、OPは持っています。弱い参照にメッセージを送信した後、アプリケーションがクラッシュすることはありません。 2.はい、あなたはこれについて正しいです、私は名前の違いに気付かなかった。 – Soberman

+0

@Sobermanここにあなたの考えに感謝します!コードに関する詳細を追加しました。これは強い/弱い参照問題であることは私には分かりません。これが依然として犯人だと思えば、拡大質問とLMKを見てみることはできますか?ありがとうございました! – esilver

関連する問題