NSFetchedResultsController with custom NSSortDescriptor - ios

I have a Person object with firstName, lastName and category(String).
I would like to create an NSSortDescriptor which allows me to fetch all Person sorted by "category" and after that sorted by firstName lastName.
Example:
The desired order is the follow:
PROSPECT, INATIVE_1Y, GC, VGC.
Then, in the category they must be arranged in alphabetical order (lastName, firstName)
I tried with NSSortDescriptor(key: , ascending: , comparator: ) but without success.
Below my code for the NSFetchRequest
let categoryDescriptor = NSSortDescriptor(key: "category", ascending: true) { (category1, category2) -> ComparisonResult in
let arrayCategory = [PROSPECT, INATIVE_1Y, GC, VGC]
let c1Index = arrayCategory.firstIndex(of: category1) ?? 0
let c2Index = arrayCategory.firstIndex(of: category2) ?? 0
if c1Index < c2Index {
return .orderedAscending
} else if c1Index > c2Index {
return .orderedDescending
}
return .orderedSame
}
objectFetchRequest.sortDescriptors?.append(categoryDescriptor)
let lastNameSortDescriptor = NSSortDescriptor(key: "lastName", ascending: true)
objectFetchRequest.sortDescriptors?.append(lastNameSortDescriptor)
let firstNameSortDescriptor = NSSortDescriptor(key: "firstName", ascending: true)
objectFetchRequest.sortDescriptors?.append(firstNameSortDescriptor)
App crash:
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLFetchRequestContext: 0x600002e82a00> , unsupported NSSortDescriptor (comparator blocks are not supported) with userInfo of (null)
2019-11-05 20:05:59.779136+0200 APP NAME [45129:1204138] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'unsupported NSSortDescriptor (comparator blocks are not supported)'
*** First throw call stack:
(
0 CoreFoundation 0x0000000110efa8db __exceptionPreprocess + 331
1 libobjc.A.dylib 0x000000010f99fac5 objc_exception_throw + 48
2 CoreData 0x00000001109ba53e -[NSSQLGenerator newSQLStatementForRequest:ignoreInheritance:countOnly:nestingLevel:nestIsWhereScoped:requestContext:] + 1646
3 CoreData 0x00000001109c4b0e -[NSSQLiteAdapter _statementForFetchRequestContext:ignoreInheritance:countOnly:nestingLevel:] + 142
4 CoreData 0x00000001108724c4 -[NSSQLiteAdapter newSelectStatementWithFetchRequestContext:ignoreInheritance:] + 116
5 CoreData 0x0000000110a0feb3 -[NSSQLFetchRequestContext _createStatement] + 67
6 CoreData 0x0000000110a0fe4e -[NSSQLFetchRequestContext fetchStatement] + 142
7 CoreData 0x0000000110a10e3b -[NSSQLFetchRequestContext executeRequestCore:] + 27
8 CoreData 0x0000000110a7a790 -[NSSQLStoreRequestContext executeRequestUsingConnection:] + 208
9 CoreData 0x0000000110a4f0eb __52-[NSSQLDefaultConnectionManager handleStoreRequest:]_block_invoke + 75
10 libdispatch.dylib 0x000000011271adb5 _dispatch_client_callout + 8
11 libdispatch.dylib 0x0000000112728d08 _dispatch_lane_barrier_sync_invoke_and_complete + 132
12 CoreData 0x0000000110a4efd0 -[NSSQLDefaultConnectionManager handleStoreRequest:] + 336
13 CoreData 0x0000000110a56c24 -[NSSQLCoreDispatchManager routeStoreRequest:] + 308
14 CoreData 0x000000011099f288 -[NSSQLCore dispatchRequest:withRetries:] + 232
15 CoreData 0x000000011099bffd -[NSSQLCore processFetchRequest:inContext:] + 93
16 CoreData 0x00000001108719ce -[NSSQLCore executeRequest:withContext:error:] + 574
17 CoreData 0x0000000110980657 __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke + 2039
18 CoreData 0x0000000110978870 -[NSPersistentStoreCoordinator _routeHeavyweightBlock:] + 288
19 CoreData 0x00000001108711a0 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 1296
20 CoreData 0x000000011086f475 -[NSManagedObjectContext executeFetchRequest:error:] + 933
21 CoreData 0x0000000110a1f9c0 __43-[NSFetchedResultsController performFetch:]_block_invoke + 448
22 CoreData 0x000000011098d104 gutsOfBlockToNSPersistentStoreCoordinatorPerform + 212
23 libdispatch.dylib 0x000000011271adb5 _dispatch_client_callout + 8
24 libdispatch.dylib 0x0000000112728d08 _dispatch_lane_barrier_sync_invoke_and_complete + 132
25 CoreData 0x0000000110978146 -[NSPersistentStoreCoordinator performBlockAndWait:] + 198
26 CoreData 0x00000001108b2a2a developerSubmittedBlockToNSManagedObjectContextPerform + 170
27 CoreData 0x00000001108b28ff -[NSManagedObjectContext performBlockAndWait:] + 239
28 CoreData 0x0000000110a1fd11 -[NSFetchedResultsController _recursivePerformBlockAndWait:withContext:] + 145
29 CoreData 0x0000000110a1f72b -[NSFetchedResultsController performFetch:] + 299
30 APP NAME 0x0000000109f25278 $s20APP_NAME22GeneralFetchControllerC14refreshResultsyySSF + 1512
31 APP NAME 0x0000000109daca74 $s20APP_NAME19LocalClientSearchVCC14refreshResultsyySSF + 164
32 APP NAME 0x0000000109f24b8b $s20APP_NAME22GeneralFetchControllerC024initializeFetchedResultsG0yyF + 619
33 APP NAME 0x0000000109f247fa $s20APP_NAME22GeneralFetchControllerC11viewDidLoadyyFyycfU_ + 58
34 APP NAME 0x0000000109f2487d $s20APP_NAME22GeneralFetchControllerC11viewDidLoadyyFyycfU_TA + 13
35 APP NAME 0x0000000109c78c4d $sIeg_IeyB_TR + 45
36 libdispatch.dylib 0x0000000112719d7f _dispatch_call_block_and_release + 12
37 libdispatch.dylib 0x000000011271adb5 _dispatch_client_callout + 8
38 libdispatch.dylib 0x0000000112728080 _dispatch_main_queue_callback_4CF + 1540
39 CoreFoundation 0x0000000110e61a79 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
40 CoreFoundation 0x0000000110e5c126 __CFRunLoopRun + 2310
41 CoreFoundation 0x0000000110e5b4d2 CFRunLoopRunSpecific + 626
42 GraphicsServices 0x00000001140b42fe GSEventRunModal + 65
43 UIKitCore 0x000000011a14ffc2 UIApplicationMain + 140
44 APP NAME 0x000000010a307ffb main + 75
45 libdyld.dylib 0x000000011278f541 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Without the categorySortDescriptor, the application does not crash.
Thanks for your help

There are (at least) two options:
Add an index attribute for the category order and update it when the category attribute is set.
Add a computed property to return the index from an array in proper order for example a safe version
var categoryIndex : Int {
switch category {
case "PROSPECT": return 0
case "INATIVE_1Y": return 1
case "GC": return 2
case "VGC": return 3
default: fatalError("category not available")
}
}
Then sort by that index.
NSSortDescriptor(key:ascending:comparator: doesn't work because block based API is not supported in SQL request, see the error message
comparator blocks are not supported

Related

How to format a core data many to many predicate with an intermediate model

I have the following core data model:
I have a view controller that contains a particular SkillGroup. I would like to make a fetch request that contains the records for all skills in that skillGroup. Normally I would think it would be something like
request.predicate = NSPredicate(format: "skill IN %#.skills", skillGroup!)
However I needed to create the intermediate "SkillGroupItem" models so that I could keep track of the displayIndex for each skill in a skillGroup. I am thinking of something like:
request.predicate = NSPredicate(format: "ANY %#.skillGroupItems.skill = skillProgress.skill", skillGroup!)
so any of the skillGroup's skillGroupItems' skill is equal to the records skillProgress object.skill...
but that throws this error:
CoreData: annotation: to-many relationship fault "skillGroupItems" for objectID 0xb9291ca50355a7c1 <x-coredata://33325602-3973-46E7-8400-45922DD97A05/SkillGroup/p1> fulfilled from database. Got 1 rows
CoreData: sql: SELECT DISTINCT t0.Z_ENT, t0.Z_PK, t0.Z_OPT, t0.ZRECORDTYPE, t0.ZTIMESTAMP, t0.ZSKILLPROGRESS, t0.ZIMAGEFILENAME, t0.ZTEXT, t0.ZTHUMBNAILFILENAME, t0.ZVIDEOFILENAME FROM ZRECORD t0 JOIN ZSKILLPROGRESS t1 ON t0.ZSKILLPROGRESS = t1.Z_PK WHERE ? = t1.ZSKILL ORDER BY t0.ZTIMESTAMP
2021-04-20 13:37:43.482875-0700 SweatNetOffline[38167:3014868] -[__NSSingleObjectSetI longLongValue]: unrecognized selector sent to instance 0x600002a69360
CoreData: annotation: total fetch execution time: 0.0013s for 0 rows.
2021-04-20 13:37:43.484519-0700 SweatNetOffline[38167:3014868] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLFetchRequestContext: 0x60000117d5e0> , -[__NSSingleObjectSetI longLongValue]: unrecognized selector sent to instance 0x600002a69360 with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLFetchRequestContext: 0x60000117d5e0> , -[__NSSingleObjectSetI longLongValue]: unrecognized selector sent to instance 0x600002a69360 with userInfo of (null)
2021-04-20 13:37:43.503515-0700 SweatNetOffline[38167:3014868] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSingleObjectSetI longLongValue]: unrecognized selector sent to instance 0x600002a69360'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff20421af6 __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007fff20177e78 objc_exception_throw + 48
2 CoreFoundation 0x00007fff204306f7 +[NSObject(NSObject) instanceMethodSignatureForSelector:] + 0
3 CoreFoundation 0x00007fff20426036 ___forwarding___ + 1489
4 CoreFoundation 0x00007fff20428068 _CF_forwarding_prep_0 + 120
5 CoreData 0x00007fff25114346 -[NSSQLiteConnection execute] + 1416
6 CoreData 0x00007fff2538acfa _newFetchedRowsForFetchPlan_ST + 1234
7 CoreData 0x00007fff2537b1c5 _executeFetchRequest + 55
8 CoreData 0x00007fff252cd352 -[NSSQLFetchRequestContext executeRequestCore:] + 41
9 CoreData 0x00007fff253430a3 -[NSSQLStoreRequestContext executeRequestUsingConnection:] + 405
10 CoreData 0x00007fff2531468f __52-[NSSQLDefaultConnectionManager handleStoreRequest:]_block_invoke + 56
11 CoreData 0x00007fff2527bdbd __37-[NSSQLiteConnection performAndWait:]_block_invoke + 28
12 libdispatch.dylib 0x00000001094479c8 _dispatch_client_callout + 8
13 libdispatch.dylib 0x0000000109456bfe _dispatch_lane_barrier_sync_invoke_and_complete + 132
14 CoreData 0x00007fff2527bca3 -[NSSQLiteConnection performAndWait:] + 134
15 CoreData 0x00007fff253145a4 -[NSSQLDefaultConnectionManager handleStoreRequest:] + 273
16 CoreData 0x00007fff2531afd8 -[NSSQLCoreDispatchManager routeStoreRequest:] + 283
17 CoreData 0x00007fff2524b284 -[NSSQLCore dispatchRequest:withRetries:] + 161
18 CoreData 0x00007fff2524681e -[NSSQLCore processFetchRequest:inContext:] + 88
19 CoreData 0x00007fff2511a461 -[NSSQLCore executeRequest:withContext:error:] + 1072
20 CoreData 0x00007fff2522595a __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke.797 + 3219
21 CoreData 0x00007fff2521e02a -[NSPersistentStoreCoordinator _routeHeavyweightBlock:] + 222
22 CoreData 0x00007fff2511993e -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 1684
23 CoreData 0x00007fff25117ef2 -[NSManagedObjectContext executeFetchRequest:error:] + 885
24 CoreData 0x00007fff252da7d0 __43-[NSFetchedResultsController performFetch:]_block_invoke + 417
25 CoreData 0x00007fff2514ce63 developerSubmittedBlockToNSManagedObjectContextPerform + 154
26 CoreData 0x00007fff2514cd4a -[NSManagedObjectContext performBlockAndWait:] + 197
27 CoreData 0x00007fff252dcc13 -[NSFetchedResultsController _recursivePerformBlockAndWait:withContext:] + 145
28 CoreData 0x00007fff252da523 -[NSFetchedResultsController performFetch:] + 231
29 SweatNetOffline 0x0000000108ece722 $s15SweatNetOffline22ProgressViewControllerC11viewDidLoadyyF + 1122
30 SweatNetOffline 0x0000000108ecf8db $s15SweatNetOffline22ProgressViewControllerC11viewDidLoadyyFTo + 43
31 UIKitCore 0x00007fff23f5e36e -[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 88
32 UIKitCore 0x00007fff23f62cd7 -[UIViewController loadViewIfRequired] + 1084
33 UIKitCore 0x00007fff23f630c1 -[UIViewController view] + 27
34 UIKitCore 0x00007fff23e82c37 -[UINavigationController _startCustomTransition:] + 1254
35 UIKitCore 0x00007fff23e991d6 -[UINavigationController _startDeferredTransitionIfNeeded:] + 684
36 UIKitCore 0x00007fff23e9a5e8 -[UINavigationController __viewWillLayoutSubviews] + 150
37 UIKitCore 0x00007fff23e7ad9e -[UILayoutContainerView layoutSubviews] + 217
38 UIKitCore 0x00007fff24bf8504 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2924
39 QuartzCore 0x00007fff27b1bc2b -[CALayer layoutSublayers] + 258
40 QuartzCore 0x00007fff27b2219d _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 575
41 QuartzCore 0x00007fff27b2df3f _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 65
42 QuartzCore 0x00007fff27a6d44c _ZN2CA7Context18commit_transactionEPNS_11TransactionEdPd + 496
43 QuartzCore 0x00007fff27aa4233 _ZN2CA11Transaction6commitEv + 783
44 QuartzCore 0x00007fff27aa53ef _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 79
45 CoreFoundation 0x00007fff2038f1f8 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
46 CoreFoundation 0x00007fff20389a77 __CFRunLoopDoObservers + 547
47 CoreFoundation 0x00007fff2038a01a __CFRunLoopRun + 1113
48 CoreFoundation 0x00007fff203896d6 CFRunLoopRunSpecific + 567
49 GraphicsServices 0x00007fff2c257db3 GSEventRunModal + 139
50 UIKitCore 0x00007fff24696cf7 -[UIApplication _run] + 912
51 UIKitCore 0x00007fff2469bba8 UIApplicationMain + 101
52 SweatNetOffline 0x0000000108e3d9fb main + 75
53 libdyld.dylib 0x00007fff2025a3e9 start + 1
54 ??? 0x0000000000000003 0x0 + 3
)
libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSingleObjectSetI longLongValue]: unrecognized selector sent to instance 0x600002a69360'
terminating with uncaught exception of type NSException
CoreSimulator 732.18.6 - Device: iPhone 11 (E5E1A675-AA38-45CE-A047-1C5569598381) - Runtime: iOS 14.4 (18D46) - DeviceType: iPhone 11
Im tripped up by how to use the ANY in this case. so any of the skillGroupItems makes sense.. but ANY skillGroup.skillGroupItems.skill seems bad to me. You can't look for a .skill on an array of skillGroupItems.
Any advice on how to accomplish this? Thanks
The predicate is parsed using the entity you are fetching (in your case, Record) as the reference point. So you would use this:
request.predicate = NSPredicate(format: "recordType == %#", givenRecordType)
to create a predicate based on the attribute recordType, and
request.predicate = NSPredicate(format: "skillProgress == %#", givenSkillProgressObject)
to create a predicate based on the relationship skillProgress (if givenSkillProgress was a SkillProgress object you already had fetched). If you do not have a SkillProgress object in memory, but you know an attribute value you want to match for it, you can use the corresponding keypath expression to refer to the attribute of the related object, eg:
request.predicate = NSPredicate(format: "skillProgress.isActive == YES")
will fetch those Record objects whose related SkillProgress object is active. You can continue to "traverse" the relationship tree by using additional elements in the key path. So:
request.predicate = NSPredicate(format: "skillProgress.skill.id == %#", givenSkillID)
will fetch those Record objects whose related SkillProgress is in turn related to a Skill whose id attribute matches the givenSkillID. For the skillGroupItems relationship (on the Skill entity), because it is to-many, you will need to use "ANY" to indicate that any of the related objects should match your criteria:
request.predicate = NSPredicate(format: "ANY skillProgress.skill.skillGroupItems == %#", givenSkillGroupItem)
The final step is then to use the skillGroup relationship from SkillGroupItem to get the full key path from Record to SkillGroup:
request.predicate = NSPredicate(format: "ANY skillProgress.skill.skillGroupItems.skillGroup == %#", givenSkillGroup)

Crash Core Data only in iOS 14

I work on an app which use CoreData, everything works fine on iOS 13 and iOS 14 with differents Xcode betas. But since Apple released the official release for iOS 14 and Xcode 12 I have a crash when I try to get some objects from CoreData.
guard let customers = Customer.mr_findAllSorted(by: "login", ascending: true) as? [Customer] else { return }
Console output :
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can't get value for 'batch' in bindings {
}.'
When I try to print the object from console log with breakpoint, I have a memory address of object but when I try to print some values of this object I have this error :
error: warning: couldn't get required object pointer (substituting NULL): Couldn't load 'self' because its value couldn't be evaluated
error: Execution was interrupted, reason: internal ObjC exception breakpoint(-5)..
The process has been returned to the state before expression evaluation.
Has anyone ever had to deal with this type of errors since the official versions ?
Thanks in advance for your help.
We're seeing this too in our app. It is only reproducible with iOS 14 and apparently the latest SDKs in Xcode 12.0.1, but we don't have any solutions or answers as to why this is occurring yet.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can't get value for 'batch' in bindings {
}.'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff2043a126 __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007fff20177f78 objc_exception_throw + 48
2 Foundation 0x00007fff2088bedc -[NSVariableExpression _expressionWithSubstitutionVariables:] + 0
3 Foundation 0x00007fff2075ac7b -[NSComparisonPredicate evaluateWithObject:substitutionVariables:] + 264
4 CoreData 0x00007fff2511ec68 -[NSDictionaryStoreMap handleFetchRequest:] + 481
5 CoreData 0x00007fff2511dfd2 -[NSMappedObjectStore executeFetchRequest:withContext:] + 230
6 CoreData 0x00007fff251e10a2 __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke.797 + 3219
7 CoreData 0x00007fff251d988d __55-[NSPersistentStoreCoordinator _routeHeavyweightBlock:]_block_invoke + 55
8 CoreData 0x00007fff251edf0a gutsOfBlockToNSPersistentStoreCoordinatorPerform + 182
9 libdispatch.dylib 0x000000010a6b0a88 _dispatch_client_callout + 8
10 libdispatch.dylib 0x000000010a6bfcac _dispatch_lane_barrier_sync_invoke_and_complete + 132
11 CoreData 0x00007fff251d9492 _perform + 169
12 CoreData 0x00007fff251d9740 -[NSPersistentStoreCoordinator _routeHeavyweightBlock:] + 172
13 CoreData 0x00007fff250d640e -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 1684
14 CoreData 0x00007fff250d49c2 -[NSManagedObjectContext executeFetchRequest:error:] + 885
15 CoreData 0x00007fff251a9d7f -[NSManagedObjectContext _parentObjectsForFetchRequest:inContext:error:] + 477
16 CoreData 0x00007fff251aa774 __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke + 603
17 CoreData 0x00007fff25109de8 internalBlockToNSManagedObjectContextPerform + 89
18 libdispatch.dylib 0x000000010a6b0a88 _dispatch_client_callout + 8
19 libdispatch.dylib 0x000000010a6bfcac _dispatch_lane_barrier_sync_invoke_and_complete + 132
20 CoreData 0x00007fff25109d6f _perform + 196
21 CoreData 0x00007fff25109b93 -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:] + 175
22 CoreData 0x00007fff250d49c2 -[NSManagedObjectContext executeFetchRequest:error:] + 885
23 CoreData 0x00007fff251a9d7f -[NSManagedObjectContext _parentObjectsForFetchRequest:inContext:error:] + 477
24 CoreData 0x00007fff251aa774 __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke + 603
25 CoreData 0x00007fff25109de8 internalBlockToNSManagedObjectContextPerform + 89
26 libdispatch.dylib 0x000000010a6b0a88 _dispatch_client_callout + 8
27 libdispatch.dylib 0x000000010a6bfe11 _dispatch_async_and_wait_invoke + 175
28 libdispatch.dylib 0x000000010a6b0a88 _dispatch_client_callout + 8
29 libdispatch.dylib 0x000000010a6bef23 _dispatch_main_queue_callback_4CF + 1152
30 CoreFoundation 0x00007fff203a8276 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
31 CoreFoundation 0x00007fff203a2b06 __CFRunLoopRun + 2685
32 CoreFoundation 0x00007fff203a1b9e CFRunLoopRunSpecific + 567
33 GraphicsServices 0x00007fff2b773db3 GSEventRunModal + 139
34 UIKitCore 0x00007fff24660af3 -[UIApplication _run] + 912
35 UIKitCore 0x00007fff24665a04 UIApplicationMain + 101
36 XXXX 0x0000000106de2d69 main + 153
37 libdyld.dylib 0x00007fff20257415 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can't get value for 'batch' in bindings {
}.'
You may set batch size to 0 [NSManagedObject MR_setDefaultBatchSize:0];, but check you performance after.

Override Core Data to-many property and return a filtered set

I’ve got an NSManagedObject with a childNodes property in its model. Now I want to override the childNodes property and return a filtered version of it, but I keep getting crashes. Here’s what I’ve got in my NSMO subclass:
- (NSOrderedSet *)childNodes {
[self willAccessValueForKey:#“childNodes”];
NSMutableOrderedSet *result = [self primitiveChildNodes];
[self didAccessValueForKey:#"childNodes”];
NSArray *filteredResult = [[result array] myCustomArrayFilteringMethod]; // let’s say this returns the first half of the array, as a contrived example
return [NSOrderedSet orderedSetWithArray:filteredResults];
}
This works alright sometimes, but I’m finding crashes like: Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSOrderedSet objectsAtIndexes:]: index 24 in index set beyond bounds [0 .. 19]’ and I’m not sure why. Call stack seems to be related to mutating a collection, but I’m mutating a copy so I’m not sure what’s happening:
0 CoreFoundation __exceptionPreprocess + 165
1 libobjc.A.dylib objc_exception_throw + 48
2 CoreFoundation -[NSOrderedSet objectsAtIndexes:] + 952
3 Foundation NSKeyValueWillChangeByOrderedToManyMutation + 568
4 Foundation NSKeyValueWillChange + 383
5 Foundation -[NSObject(NSKeyValueObserverNotification) willChange:valuesAtIndexes:forKey:] + 557
6 CoreData -[NSManagedObject(_NSInternalMethods) _excludeObject:fromPropertyWithKey:andIndex:] + 526
7 CoreData -[NSManagedObject(_NSInternalMethods) _maintainInverseRelationship:forProperty:oldDestination:newDestination:] + 254
8 CoreData -[NSManagedObject(_NSInternalMethods) _didChangeValue:forRelationship:named:withInverse:] + 567
9 Foundation NSKeyValueNotifyObserver + 347
10 Foundation NSKeyValueDidChange + 466
11 Foundation -[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] + 118
12 CoreData -[NSManagedObject didChangeValueForKey:] + 135
13 CoreData -[NSManagedObject(_NSInternalMethods) _updateFromRefreshSnapshot:includingTransients:] + 758
14 CoreData -[NSManagedObjectContext(_NestedContextSupport) _copyChildObject:toParentObject:fromChildContext:] + 567
15 CoreData -[NSManagedObjectContext(_NestedContextSupport) _parentProcessSaveRequest:inContext:error:] + 1103
16 CoreData __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke + 364
17 CoreData internalBlockToNSManagedObjectContextPerform + 84
18 libdispatch.dylib _dispatch_client_callout + 8
19 libdispatch.dylib _dispatch_barrier_sync_f_slow_invoke + 284
20 libdispatch.dylib _dispatch_client_callout + 8
21 libdispatch.dylib _dispatch_main_queue_callback_4CF + 1738
22 CoreFoundation __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
23 CoreFoundation __CFRunLoopRun + 2073
24 CoreFoundation CFRunLoopRunSpecific + 488
25 GraphicsServices GSEventRunModal + 161
26 UIKit UIApplicationMain + 171
27 My app main + 111
28 libdyld.dylib
Any suggestions? I can’t quite figure this one out.
Just don't. Add a different method which returns a filtered copy of the original relationship. Also, for the implementation just iterate the collection and add the items you want to keep to an entirely new collection, don't copy and filter.
The crash is because the array you're filtering is actually backed by the datastore, so as you filter it it's changing the contents you're iterating with the filter, and it's screwing up the original relationship.

[__NSCFArray objectForKey:]: unrecognized selector sent to instance when fetching from Core Data

I am getting the error [__NSCFArray objectForKey:]: unrecognized selector sent to instance when trying to fetch some data from my Core Data.
I am relatively new to iOS programming and don't quite understand what this error is trying to tell me. I set an exception breakpoint to figure out which line is giving me the problem and it is this line of code:
if let fetchResults = managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [User] {
Why am I getting this error and how do I resolve it? Is this related to the way I save my Core Data? I just recently did a change where I receive a JSON from the server, then process in the background and then finally save changes to my ManagedObjectContext in the main thread.
func getUser(userId: String) -> User? {
let fetchRequest = NSFetchRequest(entityName: "User")
fetchRequest.predicate = NSPredicate(format: "userId == %#", userId)
fetchRequest.fetchLimit = 1
if let fetchResults = managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [User] {
if !fetchResults.isEmpty {
return fetchResults[0]
}
else {
println("UserId \(userId) not in database")
}
}
return nil
}
Error
2014-12-06 13:09:36.087 LFDate[3162:51570] -[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0x7fb9e95c4310
2014-12-06 13:09:36.090 LFDate[3162:51570] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0x7fb9e95c4310'
*** First throw call stack:
(
0 CoreFoundation 0x00000001025c2f35 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010465ebb7 objc_exception_throw + 45
2 CoreFoundation 0x00000001025ca04d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x000000010252227c ___forwarding___ + 988
4 CoreFoundation 0x0000000102521e18 _CF_forwarding_prep_0 + 120
5 CoreFoundation 0x000000010248beaf CFDictionaryGetValue + 159
6 Foundation 0x0000000102befd78 -[NSKeyedUnarchiver initForReadingWithData:] + 1698
7 Foundation 0x0000000102c135ea +[NSKeyedUnarchiver unarchiveObjectWithData:] + 66
8 CoreData 0x000000010210b4e0 _prepareResultsFromResultSet + 3552
9 CoreData 0x0000000102108930 newFetchedRowsForFetchPlan_MT + 3296
10 CoreData 0x00000001020f53ac -[NSSQLCore objectsForFetchRequest:inContext:] + 524
11 CoreData 0x00000001020f4e2b -[NSSQLCore executeRequest:withContext:error:] + 299
12 CoreData 0x00000001021ca4f3 __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke + 3331
13 CoreData 0x00000001021d27ee gutsOfBlockToNSPersistentStoreCoordinatorPerform + 190
14 libdispatch.dylib 0x00000001052117f4 _dispatch_client_callout + 8
15 libdispatch.dylib 0x00000001051f8774 _dispatch_barrier_sync_f_invoke + 365
16 CoreData 0x00000001021c53d5 _perform + 197
17 CoreData 0x00000001020f4ac8 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 504
18 CoreData 0x00000001020f33e0 -[NSManagedObjectContext executeFetchRequest:error:] + 544
19 LFDate 0x0000000101b9c3b3 _TFC6LFDate14DatabaseHelper7getUserfS0_FSSGSqCS_4User_ + 1075
20 LFDate 0x0000000101c4ce01 _TFC6LFDate23MenuTableViewController9tableViewfS0_FTCSo11UITableView21cellForRowAtIndexPathCSo11NSIndexPath_CSo15UITableViewCell + 4689
21 LFDate 0x0000000101c4e4ff _TToFC6LFDate23MenuTableViewController9tableViewfS0_FTCSo11UITableView21cellForRowAtIndexPathCSo11NSIndexPath_CSo15UITableViewCell + 79
22 UIKit 0x000000010349d4b3 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 508
23 UIKit 0x000000010347cfb1 -[UITableView _updateVisibleCellsNow:isRecursive:] + 2846
24 UIKit 0x0000000103492e3c -[UITableView layoutSubviews] + 213
25 UIKit 0x000000010341f973 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 521
26 QuartzCore 0x000000010318ade8 -[CALayer layoutSublayers] + 150
27 QuartzCore 0x000000010317fa0e _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
28 QuartzCore 0x000000010317f87e _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
29 QuartzCore 0x00000001030ed63e _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 242
30 QuartzCore 0x00000001030ee74a _ZN2CA11Transaction6commitEv + 390
31 QuartzCore 0x00000001030eedb5 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 89
32 CoreFoundation 0x00000001024f7dc7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
33 CoreFoundation 0x00000001024f7d20 __CFRunLoopDoObservers + 368
34 CoreFoundation 0x00000001024edb53 __CFRunLoopRun + 1123
35 CoreFoundation 0x00000001024ed486 CFRunLoopRunSpecific + 470
36 GraphicsServices 0x00000001072f09f0 GSEventRunModal + 161
37 UIKit 0x00000001033a6420 UIApplicationMain + 1282
38 LFDate 0x0000000101be33ae top_level_code + 78
39 LFDate 0x0000000101be33ea main + 42
40 libdyld.dylib 0x0000000105246145 start + 1
41 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Crashing on setValue:forKey:

Crashlytics reported a crash in my app, and I have no idea of what is happening.
Here is the stacktrace:
Thread : Fatal Exception: NSInternalInconsistencyException
0 CoreFoundation 0x30080e83 __exceptionPreprocess + 130
1 libobjc.A.dylib 0x3a3dd6c7 objc_exception_throw + 38
2 CoreData 0x2fdcf941 -[NSSQLiteStatement cachedSQLiteStatement]
3 CoreData 0x2fdcf18d -[NSSQLiteConnection prepareSQLStatement:] + 52
4 CoreData 0x2fde8edf -[NSSQLChannel selectRowsWithCachedStatement:] + 58
5 CoreData 0x2fea8e1f newFetchedRowsForFetchPlan_MT + 910
6 CoreData 0x2fde8949 -[NSSQLCore fetchRowForObjectID:] + 1180
7 CoreData 0x2fde8311 -[NSSQLCore newValuesForObjectWithID:withContext:error:] + 256
8 CoreData 0x2fde762b _PFFaultHandlerLookupRow + 398
9 CoreData 0x2fde7193 _PF_FulfillDeferredFault + 218
10 CoreData 0x2fdf6449 _PF_ManagedObject_WillChangeValueForKeyIndex + 68
11 CoreData 0x2fdf636b _sharedIMPL_setvfk_core + 110
12 CoreData 0x2fe1995d _PF_Handler_Public_SetProperty + 92
13 CoreData 0x2fe1e2a9 -[NSManagedObject setValue:forKey:] + 124
14 Application 0x0004dc45 -[DateFormatter storeValue:error:] (DateFormatter.m:65)
15 Application 0x0004ee17 -[Formatter storeValue:inObject:] (Formatter.m:176)
16 Application 0x0002b5c5 -[NSManagedObject(App) setValuesForKeysWithReceivedDictionary:] (NSManagedObject+App.m:320)
17 Application 0x0002b8f3 -[NSManagedObject(App) setValuesForKeysWithReceivedDictionary:] (NSManagedObject+App.m:377)
18 Application 0x0006352d -[ODataGetOperation processResult:] (ODataGetOperation.m:220)
19 Application 0x0004420b -[ODataOperation connectionDidFinishLoading:] (ODataOperation.m:741)
20 Foundation 0x309bb47f __65-[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:]_block_invoke + 54
21 Foundation 0x309bb3c1 -[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:] + 204
22 Foundation 0x309bb2dd -[NSURLConnectionInternal _withActiveConnectionAndDelegate:] + 60
23 CFNetwork 0x2fceaf8f ___ZN27URLConnectionClient_Classic26_delegate_didFinishLoadingEU13block_pointerFvvE_block_invoke + 74
24 CFNetwork 0x2fce9b8f ___ZN27URLConnectionClient_Classic18_withDelegateAsyncEPKcU13block_pointerFvP16_CFURLConnectionPK33CFURLConnectionClientCurrent_VMaxE_block_invoke_2 + 54
25 CFNetwork 0x2fd1b337 ___ZNK17CoreSchedulingSet13_performAsyncEPKcU13block_pointerFvvE_block_invoke + 18
26 CoreFoundation 0x2ffb3ea1 CFArrayApplyFunction + 36
27 CFNetwork 0x2fc81e05 RunloopBlockContext::perform() + 164
28 CFNetwork 0x2fc81cd5 MultiplexerSource::perform() + 220
29 CFNetwork 0x2fc81b65 MultiplexerSource::_perform(void*) + 48
30 CoreFoundation 0x3004bf1f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 14
31 CoreFoundation 0x3004b3e7 __CFRunLoopDoSources0 + 206
32 CoreFoundation 0x30049bd7 __CFRunLoopRun + 630
33 CoreFoundation 0x2ffb4471 CFRunLoopRunSpecific + 524
34 CoreFoundation 0x2ffb4253 CFRunLoopRunInMode + 106
35 Foundation 0x309a2697 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 254
36 Application 0x00043b4b -[ODataOperation send] (ODataOperation.m:548)
37 Application 0x0004277f -[ODataOperation operationWillStartPreparingData] (ODataOperation.m:131)
38 Foundation 0x30a5396d __NSOQSchedule_f + 60
39 libdispatch.dylib 0x3a8c64b7 _dispatch_async_redirect_invoke + 110
40 libdispatch.dylib 0x3a8c77d9 _dispatch_root_queue_drain + 224
41 libdispatch.dylib 0x3a8c79c5 _dispatch_worker_thread2 + 56
42 libsystem_pthread.dylib 0x3a9f1dff _pthread_wqthread + 298
43 libsystem_pthread.dylib 0x3a9f1cc4 start_wqthread + 8
And there is the last method that calls setValue:forKey: in an NSManagedObject subclass
- (BOOL)storeValue:(void *)theValue error:(NSError **)theError
{
NSString * value = (__bridge NSString *)theValue;
NSString * errorMessage = nil;
if (![value length] && !isOptional)
errorMessage = [NSString stringWithFormat: NSLocalizedString(#"Value cannot be nil or empty (Date) for field %#", #""), varName];
else
{
NSDate * date = nil;
if ([value length])
{
date = [NSDate dateWithISO8601: value];
if (!date)
errorMessage = [NSString stringWithFormat: NSLocalizedString(#"Invalid date %# for field %#", #""), theValue, varName];
}
if (IvarAddress)
*((__strong NSDate **) IvarAddress) = date;
else
[currentObject setValue: date forKey: varName];
}
if (errorMessage)
{
if (theError)
*theError = [NSError errorWithDomain: AppDomain code: NSFormattingError userInfo: #{ NSLocalizedDescriptionKey: errorMessage }];
#ifdef DEBUG
NSLog(#"Formatter error: %#", errorMessage);
#endif
return NO;
}
return YES;
}
I am completely open to any suggestion :)
Update : The key exists, and the value being set is an NSDate so it's an attribute of the NSManagedObject, not a relationship.
Update 2 :
I also have another crash with that method (stack trace is not exactly the same) :
Thread : Fatal Exception: NSInternalInconsistencyException
0 CoreFoundation 0x30080e83 __exceptionPreprocess + 130
1 libobjc.A.dylib 0x3a3dd6c7 objc_exception_throw + 38
2 CoreData 0x2fddfacb -[NSSQLCore _obtainOpenChannel] + 234
3 CoreData 0x2fea8ded newFetchedRowsForFetchPlan_MT + 860
4 CoreData 0x2fde8949 -[NSSQLCore fetchRowForObjectID:] + 1180
5 CoreData 0x2fde8311 -[NSSQLCore newValuesForObjectWithID:withContext:error:] + 256
6 CoreData 0x2fde762b _PFFaultHandlerLookupRow + 398
7 CoreData 0x2fde7193 _PF_FulfillDeferredFault + 218
8 CoreData 0x2fdf6449 _PF_ManagedObject_WillChangeValueForKeyIndex + 68
9 CoreData 0x2fdf636b _sharedIMPL_setvfk_core + 110
10 CoreData 0x2fe1995d _PF_Handler_Public_SetProperty + 92
11 CoreData 0x2fe1e2a9 -[NSManagedObject setValue:forKey:] + 124
12 Application 0x000fcc45 -[DateFormatter storeValue:error:] (DateFormatter.m:65)
13 Application 0x000fde17 -[Formatter storeValue:inObject:] (Formatter.m:176)
14 Application 0x000da5c5 -[NSManagedObject(App) setValuesForKeysWithReceivedDictionary:] (NSManagedObject+.m:320)
15 Application 0x000da8f3 -[NSManagedObject(App) setValuesForKeysWithReceivedDictionary:] (NSManagedObject+.m:377)
16 Application 0x0011252d -[ODataGetOperation processResult:] (ODataGetOperation.m:220)
17 Application 0x000f320b -[ODataOperation connectionDidFinishLoading:] (ODataOperation.m:741)
18 Foundation 0x309bb47f __65-[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:]_block_invoke + 54
19 Foundation 0x309bb3c1 -[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:] + 204
20 Foundation 0x309bb2dd -[NSURLConnectionInternal _withActiveConnectionAndDelegate:] + 60
The exception message also is different :
_obtainOpenChannel -- NSSQLCore 0x15ef3780: no database channel is available
But I think they are two related issues.
So I finally found the reasons which were all related to multithreading/concurrency issues. Basically updating the same objects on two threads at the same time..
The recently added core data debug flags (-com.apple.CoreData.ConcurrencyDebug 1) were used to figure out what was happening.

Resources