libobjc.A.dylib objc_msg由于后台线程中的核心数据使用而发送崩溃
我正在调查在我的应用程序的Crashlytics控制台中报告的一次较为频繁的崩溃.
I'm looking into a somewhat frequent crash reported in my application's Crashlytics console.
我拥有的许多示例之一具有以下崩溃的线程堆栈跟踪信息:
One of the many examples I have has the following crashed thread stacktrace:
#11. Crashed: com.apple.root.default-qos
0 libobjc.A.dylib 0x22f3fa86 objc_msgSend + 5
1 Foundation 0x23ee3005 -[NSString caseInsensitiveCompare:] + 28
2 Foundation 0x23ed10bd _NSCompareObject + 28
3 Foundation 0x23ed109d _NSSortFunctionOne + 120
4 CoreFoundation 0x2373e6a3 __CFSimpleMergeSort + 114
5 CoreFoundation 0x2373e6c5 __CFSimpleMergeSort + 148
6 CoreFoundation 0x2373e6d9 __CFSimpleMergeSort + 168
7 CoreFoundation 0x2373e6c5 __CFSimpleMergeSort + 148
8 CoreFoundation 0x2373e6d9 __CFSimpleMergeSort + 168
9 CoreFoundation 0x2368ac35 CFSortIndexes + 404
10 CoreFoundation 0x2368c241 CFMergeSortArray + 176
11 Foundation 0x23ed0a9d _sortedObjectsUsingDescriptors + 456
12 Foundation 0x23f9c9fb -[NSSet(NSKeyValueSorting) sortedArrayUsingDescriptors:] + 510
13 MyApp 0x6d431 __24-[MyApp refresh]_block_invoke (MyApp.m:247)
14 CoreFoundation 0x23769499 __NSArrayEnumerate + 372
15 CoreFoundation 0x236e6c3b -[NSArray enumerateObjectsWithOptions:usingBlock:] + 62
16 MyApp 0x6d17d -[MyApp refresh] (MyApp.m:263)
17 MyApp 0xa97eb __52-[MyAppRequest updateAfterNotification:]_block_invoke (MyAppRequest.m:1175)
18 libdispatch.dylib 0x23307cbf _dispatch_call_block_and_release + 10
19 libdispatch.dylib 0x233136a1 _dispatch_root_queue_drain + 1572
20 libdispatch.dylib 0x2331307b _dispatch_worker_thread3 + 94
21 libsystem_pthread.dylib 0x234a6e0d _pthread_wqthread + 1024
22 libsystem_pthread.dylib 0x234a69fc start_wqthread + 8
崩溃的其他实例发生在同一应用程序代码中(在 MyApp
类的 refresh
方法中),但是发生在 CoreFoundation sortedArrayUsingDescriptors
方法逻辑.例如,另一个崩溃示例stacktrace具有:
Other instances of the crash occur in the same app code (in the refresh
method of MyApp
class), but during different parts of the CoreFoundation sortedArrayUsingDescriptors
method logic. For example, another crash example stacktrace has:
0 libobjc.A.dylib 0x1823cdb90 objc_msgSend + 16
1 CoreFoundation 0x182c42738 CFStringCompareWithOptionsAndLocale + 232
2 Foundation 0x183644840 _NSCompareObject + 64
3 CoreFoundation 0x182d150f4 __CFSimpleMergeSort + 196
4 CoreFoundation 0x182d15124 __CFSimpleMergeSort + 244
5 CoreFoundation 0x182d15124 __CFSimpleMergeSort + 244
6 CoreFoundation 0x182d15124 __CFSimpleMergeSort + 244
7 CoreFoundation 0x182d1513c __CFSimpleMergeSort + 268
8 CoreFoundation 0x182d15124 __CFSimpleMergeSort + 244
9 CoreFoundation 0x182d15124 __CFSimpleMergeSort + 244
10 CoreFoundation 0x182d15124 __CFSimpleMergeSort + 244
11 CoreFoundation 0x182c3b738 CFSortIndexes + 472
12 CoreFoundation 0x182c3cf58 CFMergeSortArray + 220
13 Foundation 0x1836440f8 _sortedObjectsUsingDescriptors + 564
14 Foundation 0x183725120 -[NSSet(NSKeyValueSorting) sortedArrayUsingDescriptors:] + 564
15 MyApp 0x10006f264 __24-[MyApp refresh]_block_invoke (MyApp.m:247)
刷新的应用代码为:
- (void)refresh {
NSArray *products = [self getProducts];
NSMutableArray *validProducts = [NSMutableArray array];
[products enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
Product *prod = obj;
// Convert to internal native format (MyAppProduct) for business reasons...
MyAppProduct *myAppProd = [[MyAppProduct alloc] init];
myAppProd.ID = prod.id;
myAppProd.name = prod.name;
NSArray *subProds = [prod.subProds sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"subProds" ascending:NO]]];
NSMutableArray *validSubProds = [NSMutableArray array];
[subProds enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
SubProd *subProd = obj;
// Convert to internal native format (MyAppSubProduct) for business reasons...
MyAppSubProduct *myAppSubProd = [[MyAppSubProduct alloc] initWithSubProd:subProd];
[validSubProds addObject:myAppSubProd];
}];
myAppProd.subProds = validSubProds;
myAppProd.count = [product.count integerValue];
// Add to array
[validProducts addObject:myAppProd];
}];
// Apply array to self
_products = validProducts
}
其中的getProducts是:
where getProducts is:
- (NSArray*)getProducts {
NSFetchRequest *productFetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Products"];
// Filter
NSMutableArray *productsPredicates = [NSMutableArray array];
[productsPredicates addObject:[NSPredicate predicateWithFormat:@"life_uid == %@", req.lifeUid]];
[productsPredicates addObject:[NSPredicate predicateWithFormat:@"hidden == %@", @NO]];
[productFetchRequest setPredicate:[NSCompoundPredicate andPredicateWithSubpredicates:productsPredicates]];
// Sort
NSSortDescriptor *sortProductsByName = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
[productFetchRequest setSortDescriptors:@[sortProductsByName]];
[productFetchRequest setReturnsObjectsAsFaults:NO];
[productFetchRequest setRelationshipKeyPathsForPrefetching:@[@"subprods", @"subprods.special"]];
NSManagedObjectContext *moc = [MyAppCoreDataController sharedController].mainManagedObjectContext;
NSError *error = nil;
NSArray *products = [moc executeFetchRequest:productFetchRequest error:&error];
if (error) {
NSLog(@"Error fetching products %@", error);
}
return products;
}
刷新方式如下:
- (void)updateAfterNotification:(NSNotification *)notification {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[MyApp instance] refresh];
});
}
很可能是因为您没有正确处理Core Data并发.使用 NSPrivateQueueConcurrencyType
或 NSMainQueueConcurrencyType
创建托管对象上下文时,您必须将所有核心数据访问权限放入对 performBlock 的调用中code>或
performBlockAndWait
.其中包括获取以及访问所获取对象的属性值.
Most likely it's because you're not handling Core Data concurrency correctly. When you create a managed object context using NSPrivateQueueConcurrencyType
or NSMainQueueConcurrencyType
, you must put all Core Data access inside a call to performBlock
or performBlockAndWait
. That includes fetches as well as accessing attribute values of fetched objects.
您正在使用 dispatch_async
,这不是处理Core Data并发的正确方法.您应该切换为使用 performBlock
或 performBlockAndWait
.
You're using dispatch_async
, which is not the right way to handle concurrency with Core Data. You should switch to using performBlock
or performBlockAndWait
.