I am trying to debug an error that many of my users in this area report. Everyone shows me the same stack:
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)
Line 2367 is simple:
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: });
Although the code is defined in this block, it is only 1 line, and this code does not work on this stack, because otherwise I would see cleanupMethod above myMethod .
Edit: you can see that there is a statement before sending async! Initially, I thought this crash was caused by a statement. But the line numbers never matched - the statement was many lines higher (line 2364, not 2367) - and when I tested it further, I saw that if assert is triggered, my stack will not include _block_invoke which you can add to the end of the call myMethod.
Can anyone suggest how dispatch_async can cause this behavior? Also, is there any way for me to symbolize Apple code in libsystem_c.dylib?
Binary image libsystem_c.dylib:
0x3921a000 - 0x3927efff libsystem_c.dylib armv7 <0b5d65608e6f38448cd207fbd748d372> /usr/lib/system/libsystem_c.dylib
NOTE. The object in question is a global singleton, my "data manager", if you like. It handles network requests and storage states, which might need to be shared with UIViewControllers. It is initially declared as follows:
+ (MyDataManager *)mainStore { static dispatch_once_t once; static id sharedInstance; dispatch_once(&once, ^{ sharedInstance = [[self alloc] init]; }); return sharedInstance; }
I understand the consequences of freeing an object when calling the cleanupMethod:args method ... but I thought that my global singleton would always be around and therefore always safe to call like I do in my code? Also, I don't care about saving loops, since again this should be a global single.
Is this sample code below OK?
@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