I have this crash while executing a fetch request, but from the crash report it is clear that the cause for the crash is that the predicate is nil. I have added a check for the case the startDate is nil. Is there any other potential cause for the invalid predicate I should take care of?
NSFetchRequest *calRequest = [NSFetchRequest fetchRequestWithEntityName:#"Calendar"];
calRequest.predicate = [NSPredicate predicateWithFormat:#"date >= %#", startDate];
calRequest.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"date" ascending:YES]];
NSError *error = nil;
NSArray *results = [appDelegate.managedObjectContext executeFetchRequest:calRequest error:&error];
Crash report
Thread : Fatal Exception: NSInvalidArgumentException
0 CoreFoundation 0x30534f03 __exceptionPreprocess + 130
1 libobjc.A.dylib 0x3acc9ce7 objc_exception_throw + 38
2 CoreData 0x30289f17 -[NSComparisonPredicate(_NSCoreDataSQLPredicateCategories) minimalFormInContext:] + 926
3 CoreData 0x3028952b -[NSSQLGenerator initializeContextForFetchRequest:ignoreInheritance:nestingLevel:] + 538
4 CoreData 0x30288f9f -[NSSQLGenerator newSQLStatementForFetchRequest:ignoreInheritance:countOnly:nestingLevel:] + 34
5 CoreData 0x30288e3f -[NSSQLAdapter _newSelectStatementWithFetchRequest:ignoreInheritance:] + 406
6 CoreData 0x30288aa3 -[NSSQLCore newRowsForFetchPlan:] + 114
7 CoreData 0x302881e7 -[NSSQLCore objectsForFetchRequest:inContext:] + 698
8 CoreData 0x30287c8b -[NSSQLCore executeRequest:withContext:error:] + 446
9 CoreData 0x30287539 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 2892
10 CoreData 0x3028593b -[NSManagedObjectContext executeFetchRequest:error:] + 614
11 MyApp 0x0010b769 -[Calendar calendarLoad] (Calendar.m:152)
...
Related
I am trying to perform a simple task. I have an array of dictionaries in json format. I want to create an array of objects from it.
+ (NSArray<BuyableUnit*>*)mapUnits:(NSArray<NSDictionary*>*)obj {
NSMutableArray *units = [[NSMutableArray alloc] init];
for (id each in obj) {
BuyableUnit *unit = [self mapUnit:each];
[units addObject:unit];
}
return [units copy];
}
+ (BuyableUnit*)mapUnit:(NSDictionary*)obj {
BuyableUnit *unit = [[BuyableUnit alloc] init];
[unit setType:obj[#"type"]];
[unit setUnit:obj[#"unit"]];
return unit;
}
The error I am getting:
-[BuyableUnit encodeWithCoder:]: unrecognized selector sent to instance 0x60c000293240
2018-06-15 12:51:08.140404-0400 MyApp[20978:20764150] *** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
2018-06-15 12:51:08.152077-0400 MyApp[20978:20764150] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[BuyableUnit encodeWithCoder:]: unrecognized selector sent to instance 0x60c000293240'
*** First throw call stack:
(
0 CoreFoundation 0x00000001119631e6 __exceptionPreprocess + 294
1 libobjc.A.dylib 0x0000000110ff8031 objc_exception_throw + 48
2 CoreFoundation 0x00000001119e4784 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3 CoreFoundation 0x00000001118e5898 ___forwarding___ + 1432
4 CoreFoundation 0x00000001118e5278 _CF_forwarding_prep_0 + 120
5 Foundation 0x000000010dbd05f0 _encodeObject + 1197
6 Foundation 0x000000010dbd1af0 -[NSKeyedArchiver _encodeArrayOfObjects:forKey:] + 439
7 Foundation 0x000000010dbd05f0 _encodeObject + 1197
8 Foundation 0x000000010dc02e3a +[NSKeyedArchiver archivedDataWithRootObject:] + 156
9 CoreData 0x000000010cd9d764 -[NSSQLiteConnection execute] + 2084
10 CoreData 0x000000010cef54a1 -[NSSQLiteConnection updateRow:forRequestContext:] + 817
11 CoreData 0x000000010cfbf03b _writeChangesForSaveRequest + 1419
12 CoreData 0x000000010cfc0886 _executeSaveChangesRequest + 390
13 CoreData 0x000000010ce0f812 -[NSSQLSaveChangesRequestContext executeRequestCore:] + 18
14 CoreData 0x000000010cf8f52c -[NSSQLStoreRequestContext executeRequestUsingConnection:] + 204
15 CoreData 0x000000010cf6469b __52-[NSSQLDefaultConnectionManager handleStoreRequest:]_block_invoke + 75
16 libdispatch.dylib 0x0000000112e69848 _dispatch_client_callout + 8
17 libdispatch.dylib 0x0000000112e705b8 _dispatch_queue_barrier_sync_invoke_and_complete + 374
18 CoreData 0x000000010cf64580 -[NSSQLDefaultConnectionManager handleStoreRequest:] + 336
19 CoreData 0x000000010cf6c324 -[NSSQLCoreDispatchManager routeStoreRequest:] + 308
20 CoreData 0x000000010cec2b05 -[NSSQLCore dispatchRequest:withRetries:] + 229
21 CoreData 0x000000010cebecb1 -[NSSQLCore processSaveChanges:forContext:] + 193
22 CoreData 0x000000010cda4373 -[NSSQLCore executeRequest:withContext:error:] + 787
23 CoreData 0x000000010cea568f __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke + 2015
24 CoreData 0x000000010ce9d7a8 -[NSPersistentStoreCoordinator _routeHeavyweightBlock:] + 360
25 CoreData 0x000000010cda3c02 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 642
26 CoreData 0x000000010cdcc69b -[NSManagedObjectContext save:] + 1579
Other Info:
I don't know if this is relevant, but this array of objects is a transformable property of a core data entity.
Question:
How can I have this map the json successfully?
I have tried using BuyableUnit *unit;, but it never initializes so the debugger points to 0x0(nil).
Based on the crash log, I think you need to conform to NSCoding protocol in your BuyableUnit class and implement the following methods:
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.type forKey:#"type"];
[aCoder encodeObject:self.unit forKey:#"unit"];
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super init]) {
self.type = [aDecoder decodeObjectForKey:#"type"];
self.unit = [aDecoder decodeObjectForKey:#"unit"];
}
return self;
}
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
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)
The app code in refresh is:
- (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
}
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;
}
And refresh is being called like so:
- (void)updateAfterNotification:(NSNotification *)notification {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[MyApp instance] refresh];
});
}
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.
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.
when I execute this line of code in iOS 8.3 this line crashes:
NSArray *results = [self executeFetchRequest:request inContext:context];
here is the entire function which fails:
+ (id) executeFetchRequestAndReturnFirstObject:(NSFetchRequest *)request inContext:(NSManagedObjectContext *)context
{
[request setFetchLimit:1];
NSArray *results = [self executeFetchRequest:request inContext:context];
if ([results count] == 0)
{
return nil;
}
return [results objectAtIndex:0];
}
the above function is called by:
+ (id)findFirstByAttribute:(NSString *)attribute withValue:(id)searchValue inContext:(NSManagedObjectContext *)context
{
NSFetchRequest *request = [self requestFirstByAttribute:attribute withValue:searchValue inContext:context];
[request setPropertiesToFetch:[NSArray arrayWithObject:attribute]];
return [self executeFetchRequestAndReturnFirstObject:request inContext:context];
}
It is worth noting that I am very new to iOS programming so please go easy on me, the question may not be the best and there may not be much backing code but this is due to my lack of knowledge in iOS. My android questions are generally much better than this :P If I am able to add any more detail, I will add more as I can, the crash log is below
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Bad fetch request
(NSManagedObjectResultType not compatible with contents of
propertiesToFetch)'
* First throw call stack: ( 0 CoreFoundation 0x0000000111d7dc65 exceptionPreprocess + 165 1 libobjc.A.dylib
0x0000000110fafbb7 objc_exception_throw + 45 2 CoreData
0x00000001112ecb6e -[NSSQLGenerator
newSQLStatementForRequest:ignoreInheritance:countOnly:nestingLevel:] +
1646 3 CoreData 0x00000001112d8dc4
-[NSSQLAdapter _statementForFetchRequest:ignoreInheritance:countOnly:nestingLevel:] + 244 4 CoreData 0x00000001111f0e0c
-[NSSQLAdapter _newSelectStatementWithFetchRequest:ignoreInheritance:] + 316 5 CoreData 0x00000001111f0a86 -[NSSQLCore newRowsForFetchPlan:] + 118 6 CoreData 0x00000001111f033c -[NSSQLCore objectsForFetchRequest:inContext:] +
524 7 CoreData 0x00000001111efdbb
-[NSSQLCore executeRequest:withContext:error:] + 299 8 CoreData 0x00000001112caa6c __65-[NSPersistentStoreCoordinator
executeRequest:withContext:error:]_block_invoke + 3356 9 CoreData
0x00000001112d3c30 gutsOfBlockToNSPersistentStoreCoordinatorPerform +
192 10 libdispatch.dylib 0x0000000114e29614
_dispatch_client_callout + 8 11 libdispatch.dylib 0x0000000114e0f002 _dispatch_barrier_sync_f_invoke + 365 12 CoreData
0x00000001112c5245 _perform + 197 13 CoreData
0x00000001111efa58 -[NSPersistentStoreCoordinator
executeRequest:withContext:error:] + 504 14 CoreData
0x00000001111ee2ca -[NSManagedObjectContext
executeFetchRequest:error:] + 586 15 HawkExpress
0x000000010e52438e +[NSManagedObject(MagicalRecord)
executeFetchRequest:inContext:] + 62 16 HawkExpress
0x000000010e52446e +[NSManagedObject(MagicalRecord)
executeFetchRequestAndReturnFirstObject:inContext:] + 78 17
HawkExpress 0x000000010e5261fc
+[NSManagedObject(MagicalRecord) findFirstByAttribute:withValue:inContext:] + 140 18 HawkExpress
0x000000010e526274 +[NSManagedObject(MagicalRecord)
findFirstByAttribute:withValue:] + 100 19 HawkExpress
0x000000010e52aa54 +[FavouritesManager doesFavouriteExist:] + 84 20
HawkExpress 0x000000010e4de4a7
-[BookCabViewController tableView:cellForRowAtIndexPath:] + 2087 21 UIKit 0x00000001124b9a28 -[UITableView
_createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 508 22 UIKit 0x0000000112498248 -[UITableView
_updateVisibleCellsNow:isRecursive:] + 2853 23 UIKit 0x00000001124ae8a9 -[UITableView layoutSubviews] + 210 24 UIKit
0x0000000112438a2b -[UIView(CALayerDelegate) layoutSublayersOfLayer:]
+ 536 25 QuartzCore 0x000000010fdfbec2 -[CALayer layoutSublayers] + 146 26 QuartzCore 0x000000010fdf06d6 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE +
380 27 QuartzCore 0x000000010fdf0546
_ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24 28 QuartzCore 0x000000010fd5c886
_ZN2CA7Context18commit_transactionEPNS_11TransactionE + 242 29 QuartzCore 0x000000010fd5da3a
_ZN2CA11Transaction6commitEv + 462 30 QuartzCore 0x000000010fd5e0eb
_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 89 31 CoreFoundation 0x0000000111cb0ca7
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION + 23 32 CoreFoundation 0x0000000111cb0c00
__CFRunLoopDoObservers + 368 33 CoreFoundation 0x0000000111ca6a33 __CFRunLoopRun + 1123 34 CoreFoundation
0x0000000111ca6366 CFRunLoopRunSpecific + 470 35 GraphicsServices
0x0000000114a34a3e GSEventRunModal + 161 36 UIKit
0x00000001123b8900 UIApplicationMain + 1282 37 HawkExpress
0x000000010e4baa23 main + 99 38 libdyld.dylib
0x0000000114e5d145 start + 1 ) libc++abi.dylib: terminating with
uncaught exception of type NSException (lldb)
You need to check if the NSArray results is nil before you can do a count.
if (array != nil) {
NSUInteger count = [array count]; // May be 0 if the object has been deleted.
//
}
else {
// Deal with error.
}
See https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdFetching.html
Your NSFetchRequest object is probably not constructed correctly.
Here is a valid NSFetchRequest example. Find plenty more by googling "NSFetchRequest example".
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == %#", aTitle]; //<----- (a)
[request setEntity:[NSEntityDescription entityForName:#"Person" inManagedObjectContext:moc]];
[request setPredicate:predicate];
Be careful at (a), the string must strictly follow the predicate format string pattern (see NSPrediate class reference), name must be a property of Person entity in your managed object model
And the problem is in this part
NSFetchRequest *request = [self requestFirstByAttribute:attribute withValue:searchValue inContext:context];
[request setPropertiesToFetch:[NSArray arrayWithObject:attribute]];
So, post the code for method [self requestFirstByAttribute... ] if still not resolved.
tried to comment out the line [request setPropertiesToFetch:[NSArray arrayWithObject:attribute]];?
'Bad fetch request (NSManagedObjectResultType not compatible with contents of propertiesToFetch)' means, that you seem to expect the default NSFetchRequestResultType (NSManagedObjectResultType). But you request not to fetch the complete Entity, but only ONE attribute (why, just by the way? Your method provide an expected value and gives only one attribute to fetch).
My solution to this:
- (id)findEntityNamed:(NSString*)entity withKeyPath:(NSString*)path equalTo:(id)value
{
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:entity
inManagedObjectContext:context]];
NSPredicate* predicate =
[NSComparisonPredicate predicateWithLeftExpression:[NSExpression expressionForKeyPath:path]
rightExpression:[NSExpression expressionForConstantValue:value]
modifier:NSDirectPredicateModifier
type:NSEqualToPredicateOperatorType
options:0];
[fetchRequest setPredicate:predicate];
[fetchRequest setFetchLimit:1]; // ONLY 1 OBJECT IS FETCHED!
NSError* err = nil;
NSArray* results = [context executeFetchRequest:fetchRequest error:&err];
[fetchRequest release];
if( err )
{
// do logging stuff etc.
}
if( [results count] < 1 )
return nil;
return [results lastObject];
}
you can try this and tell if this is more like you was looking for
In my mac OS X application, I am getting this EXC_BAD_ACCESS signal in Core Data part (NSPredicate).
Code for reference:
[self.managedObjectContext reset];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[self.managedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
//Setting Entity to be Queried
NSEntityDescription *entity = [NSEntityDescription entityForName:#"FileTable"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:#"_pk" ascending:NO]]];
[fetchRequest setEntity:entity];
NSError* error;
NSString *uuid = uniqueId;
NSPredicate *pred = [NSPredicate predicateWithFormat:#"uuid = %#", uuid];
[fetchRequest setPredicate:pred];
// Query on managedObjectContext With Generated fetchRequest
NSArray *fetchedRecords = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
// NSLog(#"fetchedRecords %#",fetchedRecords);
// Returning Fetched Records
return fetchedRecords;
I caught the stack trace for the above scenario
(
0 WEPA-PrintApp 0x000000010a235969 WEPA-PrintApp + 47465
1 CoreFoundation 0x00007fff9216acbc __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
2 CoreFoundation 0x00007fff9205c1b4 _CFXNotificationPost + 3140
3 Foundation 0x00007fff8c528ea1 -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
4 AppKit 0x00007fff8f95725b -[NSApplication _postDidFinishNotification] + 291
5 AppKit 0x00007fff8f956fc6 -[NSApplication _sendFinishLaunchingNotification] + 191
6 AppKit 0x00007fff8f953dc6 -[NSApplication(NSAppleEventHandling) _handleAEOpenEvent:] + 574
7 AppKit 0x00007fff8f953805 -[NSApplication(NSAppleEventHandling) _handleCoreEvent:withReplyEvent:] + 244
8 Foundation 0x00007fff8c548458 -[NSAppleEventManager dispatchRawAppleEvent:withRawReply:handlerRefCon:] + 290
9 Foundation 0x00007fff8c5482c9 _NSAppleEventManagerGenericHandler + 102
10 AE 0x00007fff9047a99c _Z20aeDispatchAppleEventPK6AEDescPS_jPh + 531
11 AE 0x00007fff9047a719 _ZL25dispatchEventAndSendReplyPK6AEDescPS_ + 31
12 AE 0x00007fff9047a623 aeProcessAppleEvent + 295
13 HIToolbox 0x00007fff93e1b37e AEProcessAppleEvent + 56
14 AppKit 0x00007fff8f94fec6 _DPSNextEvent + 2665
15 AppKit 0x00007fff8f94efd0 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 194
16 AppKit 0x00007fff8f942f73 -[NSApplication run] + 594
17 AppKit 0x00007fff8f92e424 NSApplicationMain + 1832
18 WEPA-PrintApp 0x000000010a250f96 WEPA-PrintApp + 159638
19 libdyld.dylib 0x00007fff917ae5c9 start + 1
)
This crash occurs not all the time. And uuid here is NSString. Can any one provide the solution to accomplish the issue?
My iOS app is crashing when doing two calls to countForFetchRequest at the same time on the same private queue NSManagedObjectContext using performBlock.
I setup my childContext like this
_childContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_childContext setParentContext:self.managedObjectContext];
And this is my performBlock that calls countForFetchRequest
[self.childContext performBlock:^{
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"History"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"url == %#", url];
NSError *error = nil;
NSUInteger num = [self.childContext countForFetchRequest:fetchRequest error:&error];
if(error != nil){
NSLog(#"Error getting count for history url %# %#", url, error);
return;
}
if(num > 0){ // Already have this in the history, don't re-add it
return;
}
History *history = (History *)[NSEntityDescription insertNewObjectForEntityForName:#"History" inManagedObjectContext:self.childContext];
history.url = url;
history.title = title;
if(![self.childContext save:&error]){
NSLog(#"Error occurred saving history item %# %# %#", title, url, error);
}
}];
And here is the crash log:
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x3a427350 __pthread_kill + 8
1 libsystem_c.dylib 0x3a39e11e pthread_kill + 54
2 libsystem_c.dylib 0x3a3da96e abort + 90
3 libc++abi.dylib 0x39978d4a abort_message + 70
4 libc++abi.dylib 0x39975ff4 default_terminate() + 20
5 libobjc.A.dylib 0x39f29a74 _objc_terminate() + 144
6 libc++abi.dylib 0x39976078 safe_handler_caller(void (*)()) + 76
7 libc++abi.dylib 0x39976110 std::terminate() + 16
8 libc++abi.dylib 0x39977594 __cxa_rethrow + 84
9 libobjc.A.dylib 0x39f299cc objc_exception_rethrow + 8
10 CoreData 0x31e868e0 -[NSManagedObjectContext(_NSInternalAdditions) _countWithNoChangesForRequest:error:] + 764
11 CoreData 0x31e833fe -[NSManagedObjectContext countForFetchRequest:error:] + 1062
12 CoreData 0x31e92470 __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke_0 + 460
13 libdispatch.dylib 0x3a345d26 _dispatch_barrier_sync_f_slow_invoke + 82
14 libdispatch.dylib 0x3a3404b4 _dispatch_client_callout + 20
15 libdispatch.dylib 0x3a3451b8 _dispatch_main_queue_callback_4CF$VARIANT$mp + 220
16 CoreFoundation 0x3205cf36 __CFRunLoopRun + 1286
17 CoreFoundation 0x31fcfeb8 CFRunLoopRunSpecific + 352
18 CoreFoundation 0x31fcfd44 CFRunLoopRunInMode + 100
19 GraphicsServices 0x35b992e6 GSEventRunModal + 70
20 UIKit 0x33ee52fc UIApplicationMain + 1116
21 Accountable2You Mobile 0x000e5d28 0xe4000 + 7464
22 Accountable2You Mobile 0x000e5cc4 0xe4000 + 7364
Thread 1 name: Dispatch queue: NSManagedObjectContext Queue
Thread 1:
0 libsystem_kernel.dylib 0x3a416f04 semaphore_wait_trap + 8
1 libdispatch.dylib 0x3a3462fc _dispatch_thread_semaphore_wait$VARIANT$mp + 8
2 libdispatch.dylib 0x3a34487c _dispatch_barrier_sync_f_slow + 96
3 CoreData 0x31e82df2 _perform + 166
4 CoreData 0x31e921c6 -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:] + 238
5 CoreData 0x31e86770 -[NSManagedObjectContext(_NSInternalAdditions) _countWithNoChangesForRequest:error:] + 396
6 CoreData 0x31e833fe -[NSManagedObjectContext countForFetchRequest:error:] + 1062
7 Accountable2You Mobile 0x000ee7be 0xe4000 + 42942
8 CoreData 0x31e86072 developerSubmittedBlockToNSManagedObjectContextPerform_privateasync + 66
9 libdispatch.dylib 0x3a344eca _dispatch_queue_drain$VARIANT$mp + 138
10 libdispatch.dylib 0x3a344dbc _dispatch_queue_invoke$VARIANT$mp + 36
11 libdispatch.dylib 0x3a34591a _dispatch_root_queue_drain + 182
12 libdispatch.dylib 0x3a345abc _dispatch_worker_thread2 + 80
13 libsystem_c.dylib 0x3a375a0e _pthread_wqthread + 358
14 libsystem_c.dylib 0x3a3758a0 start_wqthread + 4
Am I using the performBlock correctly?
Edit: More details
The performBlock is being called in a webViewDidFinishLoad:webView delegate method. I have multiple UIWebViews and when they finish loading they are calling the delegate method which is in turn calling the performBlock to see if it needs to add the url to the core data database.
You can encapsulate the method causing the crash in:
#synchronized(self) {
[object yourMethod];
}
This will make sure that even while multithreading, the piece of code inside will be running just once at a time ... other threads will just have to wait. Frankly, this will work only if the cause of the crash is the concurrency.