I have a entity A, it has a relationship B.
Here is a array fetched from CoreData:
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"isSynchronized = NO"];
NSManagedObjectContext *context = [NSManagedObjectContext MR_contextForCurrentThread];
NSArray * newWordsToSynchronize = [A MR_findAllWithPredicate:predicate inContext:context];
NSMutableArray * newWordsParameters = [NSMutableArray arrayWithCapacity:[asToSynchronize count]];
[newWordsToSynchronize enumerateObjectsUsingBlock:^(A * a, NSUInteger idx, BOOL * stop) {
NSLog(#"============= may have some problem ============");
NSLog(#"[a hasFaultForRelationshipNamed:#\"b\"] = %d", [a hasFaultForRelationshipNamed:#"b"]);
NSLog(#"a.word = %#", a.word);
NSLog(#"a.b.objectID = %#", a.b.objectID);
NSLog(#"a.managedObjectContext = %#", a.managedObjectContext);
NSLog(#"a.b.managedObjectContext = %#", [a.b managedObjectContext]);
NSLog(#"a.b.managedObjectContext = %#", [a.b managedObjectContext]);
NSLog(#"a.managedObjectContext = %#", a.managedObjectContext);
NSDictionary *paramDictionary = #{
#"nbook" : a.b.name,
#"lang" : a.lang,
...
};
[newWordsParameters addObject:paramDictionary];
}];
The [a.b managedObjectContext] method may return nil when I call it at second time and then the app goes crash.
Crash log from console:
2014-01-20 14:29:14.561 MyApp[10563:2e07] a.b.objectID = 0x1754e940 <x-coredata://DFC4F956-D5AC-4264-8717-C07090CA9547/B/p1>
2014-01-20 14:29:14.561 MyApp[10563:2e07] a.managedObjectContext = <NSManagedObjectContext: 0x1754bc00>
2014-01-20 14:29:14.561 MyApp[10563:2e07] a.b.managedObjectContext = <NSManagedObjectContext: 0x1754bc00>
2014-01-20 14:29:14.562 MyApp[10563:2e07] a.b.managedObjectContext = (null)
*** Terminating app due to uncaught exception 'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0x1754e940 <x-coredata://DFC4F956-D5AC-4264-8717-C07090CA9547/B/p1>''
*** First throw call stack:
(
0 CoreFoundation 0x037495e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x034cc8b6 objc_exception_throw + 44
2 CoreData 0x031a233b _PFFaultHandlerLookupRow + 2715
3 CoreData 0x031a1897 -[NSFaultHandler fulfillFault:withContext:forIndex:] + 39
4 CoreData 0x031a1473 _PF_FulfillDeferredFault + 259
5 CoreData 0x031a12c6 _sharedIMPL_pvfk_core + 70
6 CoreData 0x031e7130 _pvfk_5 + 32
7 MyApp 0x00181b00 __68-[CichangAHTTPEngine synchronizeAsOnCompletion:failure:]_block_invoke + 1760
8 CoreFoundation 0x037435eb __NSArrayEnumerate + 571
9 CoreFoundation 0x03743196 -[NSArray enumerateObjectsWithOptions:usingBlock:] + 102
10 CoreFoundation 0x037430a5 -[NSArray enumerateObjectsUsingBlock:] + 53
11 MyApp 0x0018105b -[CichangAHTTPEngine synchronizeAsOnCompletion:failure:] + 1179
12 MyApp 0x00185d9e __65-[CichangAHTTPEngine downloader:didFinishedDownloadObject:]_block_invoke_3 + 2030
13 libdispatch.dylib 0x040717f8 _dispatch_call_block_and_release + 15
14 libdispatch.dylib 0x040864b0 _dispatch_client_callout + 14
15 libdispatch.dylib 0x04074eeb _dispatch_root_queue_drain + 287
16 libdispatch.dylib 0x04075137 _dispatch_worker_thread2 + 39
17 libsystem_pthread.dylib 0x04412dab _pthread_wqthread + 336
18 libsystem_pthread.dylib 0x04416cce start_wqthread + 30
)
libc++abi.dylib: terminating with uncaught exception of type _NSCoreDataException
I found that B will be deallocated after first [a.b managedObjectContext] calling.
I think it was mainly caused by Core Data 1550 error (If I do not call [a.b managedObjectContext], Core Data will reports "The operation couldn’t be completed. (Cocoa error 1550.)"). But what may cause 1550 error and how to fix it?
1550 error report:
Error Domain=NSCocoaErrorDomain Code=1550 "The operation couldn’t be completed. (Cocoa error 1550.)" UserInfo=0x167269c0 {NSLocalizedDescription=The operation couldn’t be completed. (Cocoa error 1550.), Dangling reference to an invalid object.=null, NSValidationErrorObject=<A: 0x16bab420> (entity: A; id: 0x16baae50 <x-coredata://A85EE9AB-97C1-43C1-B92E-A6C906F0C1A8/A/p168> ; data: {
date = "2014-01-21 02:32:00 +0000";
expect = "2014-01-21 02:31:59 +0000";
isSynchronized = 1;
lang = en;
last = "2014-01-21 02:01:59 +0000";
level = 1;
b = "0x16bab460 <x-coredata://A85EE9AB-97C1-43C1-B92E-A6C906F0C1A8/B/p1>";
status = "-1";
studycount = 0;
trans = "v. \U6d4b\U91cf\Uff0c\U6743\U8861 ";
word = measure;
}), NSAffectedObjectsErrorKey=(
"<B: 0x16babd70> (entity: B; id: 0x16bab460 <x-coredata://A85EE9AB-97C1-43C1-B92E-A6C906F0C1A8/B/p1> ; data: <fault>)"
), NSValidationErrorKey=newWordBook, NSValidationErrorValue=<B: 0x16babd70> (entity: B; id: 0x16bab460 <x-coredata://A85EE9AB-97C1-43C1-B92E-A6C906F0C1A8/B/p1> ; data: <fault>), NSValidationErrorShouldAttemptRecoveryKey=true}
If the 1550 error happened, "CoreData could not fulfill a fault" crash will more easer to cause.
“Core Data could not fulfill fault” really means that there was a deletion. There was data in the persistent store. Then managed object representing this data was created. The object was a fault. Then the data in the store was deleted. Then some property of an object was accessed and Core Data tried to fulfill the fault, but couldn’t.
If you’re not doing explicit deletions, then also make sure that implicit deletions are not happening. Deletion behind the scenes could happen when one of your relationships was configured with the cascade deletion rule.
In your example this could happen if the relationship from A to B was configured with cascade rule, and object A was deleted.
Related
I Have an extremely strange issue with the GMSPolygon object.
Just out of nowhere my code crashes with the error "Unrecognized selector send to instance 0x...."
(Yes it worked all day, and suddenly it starts crashing)
I am using an array of Polygons (to keep track of them and update them dynamically) and I initialize them as follows in my -viewDidLoad:
GMSPolygon *myPoly[50];
--
GMSMutablePath *path = [[GMSMutablePath alloc] init];
// set some fake coordinates, initializing a Polygon with an empty path seems to crash as well...
[path addCoordinate:CLLocationCoordinate2DMake(1,0)];
[path addCoordinate:CLLocationCoordinate2DMake(-1,0)];
[path addCoordinate:CLLocationCoordinate2DMake(0,1)];
for (int i=0;i<50;i++) {
myPoly[i] = [GMSPolygon polygonWithPath:path];
myPoly[i].map = nil;
}
Later on in my program I try to acces the object again in the same way, first set it to nil so it will be removed from the map, and then update and if necessary display it again
for (int i=0;i<50;i++) {
myPoly[i] = [GMSPolygon polygonWithPath:path];
myPoly[i].map = nil; <--------- CRASH
// Do other stuf here, update the Polygon data and if needed
// display again as follows:
myPoly[i].map = mapView_;
}
But it seems to crash..
Same thing happens if I put the GMSPolygon in an NSMutable array. Initializing the array is fine, but getting the GMSPolygon out of the array and setting the .map property gives the same crash..
UPDATE:
It seems be caused by the object Memory locations.. If it works fine, memory locations are as follows:
[0] GMSPolygon * 0x1558ed750 0x00000001558ed750 <--- viewDidLoad for-loop
[0] GMSPolygon * 0x1558ed750 0x00000001558ed750 <--- other function for-loop
When it crashes
[0] GMSPolygon * 0x12e7cbf30 0x000000012e7cbf30 <--- viewDidLoad for-loop
[0] GMSPolygon * 0x129d36630 0x0000000129d36630 <--- other function for-loop
The object is only initialized once in the viewDidLoad, nowhere else!
It obviously explains the crash if the objects memory location are different.. but what's happening here?
Any one an idea why?
UPDATE 2, Got Crash log now:
2016-04-14 15:16:49.618 myApp[1130:240689] -[GMSMutablePath setMap:]: unrecognized selector sent to instance 0x1540bb560
2016-04-14 15:16:49.627 myApp[1130:240689] void uncaughtExceptionHandler(NSException *__strong) [Line 354] CRASH: -[GMSMutablePath setMap:]: unrecognized selector sent to instance 0x1540bb560
2016-04-14 15:16:49.688 myApp[1130:240689] void uncaughtExceptionHandler(NSException *__strong) [Line 355] Stack Trace: (
0 CoreFoundation 0x0000000182ebee50 <redacted> + 148
1 libobjc.A.dylib 0x0000000182523f80 objc_exception_throw + 56
2 CoreFoundation 0x0000000182ec5ccc <redacted> + 0
3 CoreFoundation 0x0000000182ec2c74 <redacted> + 872
4 CoreFoundation 0x0000000182dc0d1c _CF_forwarding_prep_0 + 92
5 myApp 0x00000001001115a0 -[mapViewController plotPoly] + 2028
6 myApp 0x000000010012c944 -[mapViewController mapView:didChangeCameraPosition:] + 556
7 CoreFoundation 0x0000000182ec4ae0 <redacted> + 144
8 CoreFoundation 0x0000000182dbc548 <redacted> + 284
9 CoreFoundation 0x0000000182dc0e70 <redacted> + 60
10 myApp 0x0000000100203370 -[GMSDelegateForward forwardInvocation:] + 108
11 CoreFoundation 0x0000000182ec2aa4 <redacted> + 408
12 CoreFoundation 0x0000000182dc0d1c _CF_forwarding_prep_0 + 92
13 myApp 0x0000000100188fec -[GMSMapView updateWithCamera:] + 176
14 Foundation 0x0000000183893ffc <redacted> + 340
15 CoreFoundation 0x0000000182e75124 <redacted> + 24
16 CoreFoundation 0x0000000182e74bb8 <redacted> + 540
17 CoreFoundation 0x0000000182e728b8 <redacted> + 724
18 CoreFoundation 0x0000000182d9cd10 CFRunLoopRunSpecific + 384
19 GraphicsServices 0x0000000184684088 GSEventRunModal + 180
20 UIKit 0x0000000188069f70 UIApplicationMain + 204
21 myApp 0x000000010013dd3c main + 124
22 libdyld.dylib 0x000000018293a8b8 <redacted> + 4)
2016-04-14 15:16:49.700 myApp[1130:240689] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[GMSMutablePath setMap:]: unrecognized selector sent to instance 0x1540bb560'
*** First throw call stack:
(0x182ebee38 0x182523f80 0x182ec5ccc 0x182ec2c74 0x182dc0d1c 0x1001115a0
0x10012c944 0x182ec4ae0 0x182dbc548 0x182dc0e70 0x100203370 0x182ec2aa4
0x182dc0d1c 0x100188fec 0x183893ffc 0x182e75124 0x182e74bb8 0x182e728b8
0x182d9cd10 0x184684088 0x188069f70 0x10013dd3c 0x18293a8b8)
libc++abi.dylib: terminating with uncaught exception of type NSException
I am stunned now.
The initial initialization works fine, the Polygons are drawn as the should, but as soon as I call the function to redraw the polygons, the crash happens.. and strange enough now I see why it crashes, but I don't understand.. It changes the first 5 array entry's to GMSMutablePath and GMSPolyLine , instead of GMSPolygon ?!, see link to picture below.. And have no idea why, because I am 100% sure the array of GMSPolygon is not touched anywhere else in the mean time..
Picture of of change in Array type
I can't post a comment yet due to my reputation. Just like what Dan said, use NSArray or NSMutableArray to store your objects. Then do your stuff.
UPDATE:
Here are my suggestions:
Add All Exceptions to your breakpoint navigator.
Try testing your code without loop.
Try adding float values as your coordinates.
See example code below:
GMSMutablePath *prettyPoly = [GMSMutablePath path];
[prettyPoly addCoordinate:CLLocationCoordinate2DMake(52.506191, 1.83197)];
[prettyPoly addCoordinate:CLLocationCoordinate2DMake(52.05249, 1.650696)];
[prettyPoly addCoordinate:CLLocationCoordinate2DMake(51.92225, 1.321106)];
[prettyPoly addCoordinate:CLLocationCoordinate2DMake(51.996719, 1.219482)];
[prettyPoly addCoordinate:CLLocationCoordinate2DMake(52.049112, 1.244202)];
[prettyPoly addCoordinate:CLLocationCoordinate2DMake(52.197507, 1.334839)];
[prettyPoly addCoordinate:CLLocationCoordinate2DMake(52.519564, 1.801758)];
GMSPolygon *polygon = [GMSPolygon polygonWithPath: prettyPoly];
polygon.fillColor = [UIColor colorWithRed:0 green:0.25 blue:0 alpha:0.3];
polygon.strokeColor = [UIColor greenColor];
polygon.strokeWidth = 5;
polygon.map = self.googleMap;
If everything failed:
- Refer to this doc: https://developers.google.com/maps/documentation/ios-sdk/reference/interface_g_m_s_polygon#properties
How about you try Polyline class and see this example: https://developers.google.com/maps/documentation/ios-sdk/shapes#add_a_polyline
Last, try seeking help from Google Forum, or from the repo of that library you are using.
I am attempting to use the addFetchRequestBlock method to remove orphaned objects from an API call I'm making. However, the objects I'd like it to remove are the objects from various relationships to the main object.
The outermost object is the Day object which has many FoodEntry objects.
API call to /nutrition/days/2014-07-14
RKManagedObjectRequestOperation *operation = [[RKObjectManager sharedManager] appropriateObjectRequestOperationWithObject:nil method:RKRequestMethodGET path:[NSString stringWithFormat:#"nutrition/days/%#", dateFormatted] parameters:nil];
[operation setDeletesOrphanedObjects:YES];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
self.day = (Day *)mappingResult.firstObject;
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
failure([operation decodeErrors]);
}];
[RKObjectManager.sharedManager enqueueObjectRequestOperation:operation];
results in:
{
"day": {
"date": "2014-07-24",
"food_entries": [
{
"id": "53d14b973861330009de0300",
"consumed_on": "2014-07-24",
"food_id": 36394,
"serving_id": 34187,
"quantity": 1,
"name": "Waffle",
"brand": null,
"description": "1 cup slices",
"meal_type": "breakfast",
"calories": 25,
"carbohydrate": 6.68,
"protein": 0.48,
"fat": 0.04,
"saturated_fat": null,
"polyunsaturated_fat": null,
"monounsaturated_fat": null,
"trans_fat": null,
"cholesterol": 0,
"sodium": 9,
"potassium": 43,
"fiber": null,
"sugar": null
},
{
"id": "53d151c138313800099c0100",
"consumed_on": "2014-07-24",
"food_id": 38720,
"serving_id": 48329,
"quantity": 0.5,
"name": "Australian Lamb Leg (Sirloin Chops, Boneless, Trimmed to 1/8\" Fat)",
"brand": null,
"description": "1 lb",
"meal_type": "breakfast",
"calories": 471.5,
"carbohydrate": 0,
"protein": 41.57,
"fat": 32.615,
"saturated_fat": 15.6445,
"polyunsaturated_fat": 1.472,
"monounsaturated_fat": 13.3315,
"trans_fat": null,
"cholesterol": 149.5,
"sodium": 134,
"potassium": 698.5,
"fiber": null,
"sugar": null
}]
}
}
The fetch request block I'm using is as follows:
[[RKObjectManager sharedManager] addFetchRequestBlock:^NSFetchRequest *(NSURL *URL) {
RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:#"nutrition/days/:date"];
NSDictionary *argsDict = nil;
BOOL match = [pathMatcher matchesPath:[URL relativePath] tokenizeQueryStrings:NO parsedArguments:&argsDict];
NSDate *date;
if (match) {
date = [[[RDFormatters sharedManager] dashFormatUTC] dateFromString:[argsDict objectForKey:#"date"]];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"FoodEntry"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"day.date = %#", date];
return fetchRequest;
}
return nil;
}];
This FetchRequest returns all the FoodEntries associated with the day call, however, I do not think I'm performing the call correctly. I realize this because
It crashes (duh!)
The response of the API call is usually a Day object, but after performing the FetchRequest it becomes a FoodEntry object – the very same FoodEntry object I'm attempting to delete.
Is there a way to delete orphaned objects in relationships via Restkit? What's the proper method for this?
================================
Here is the crash log
2014-07-25 08:38:18.158 Euco[6918:60b] I restkit.network:RKObjectRequestOperation.m:180 GET 'https://example.com/api/v1/nutrition/days/2014-07-24'
2014-07-25 08:38:18.831 Euco[6918:f03] I restkit.network:RKObjectRequestOperation.m:250 GET 'https://example.com/api/v1/nutrition/days/2014-07-24' (200 OK / 4 objects) [request=0.6671s mapping=0.0053s total=0.6881s]
2014-07-25 08:38:18.831 Euco[6918:60b] -[FoodEntry nutrition_plan]: unrecognized selector sent to instance 0x10ab5ff20
(lldb) po self.day
<FoodEntry: 0x10ab5ff20> (entity: FoodEntry; id: 0xd000000000040012 <x-coredata://1CAD1FBC-F8EE-4A9C-A1B4-7DCDF2A5F1D7/FoodEntry/p1> ; data: <fault>)
2014-07-25 08:38:58.103 Euco[6918:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[FoodEntry nutrition_plan]: unrecognized selector sent to instance 0x10ab5ff20'
*** First throw call stack:
(
0 CoreFoundation 0x00000001038a1495 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001032c299e objc_exception_throw + 43
2 CoreFoundation 0x000000010393265d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x0000000103892d8d ___forwarding___ + 973
4 CoreFoundation 0x0000000103892938 _CF_forwarding_prep_0 + 120
5 Euco 0x0000000100036ff8 -[JournalNutritionViewController numberOfSectionsInTableView:] + 88
6 UIKit 0x00000001024ec8e2 -[UITableViewRowData(UITableViewRowDataPrivate) _updateNumSections] + 86
7 UIKit 0x00000001024ed5b5 -[UITableViewRowData invalidateAllSections] + 66
8 UIKit 0x000000010238b0cc -[UITableView _updateRowData] + 191
9 UIKit 0x000000010239c225 -[UITableView noteNumberOfRowsChanged] + 91
10 UIKit 0x000000010239bd27 -[UITableView reloadData] + 717
11 Euco 0x00000001000368c8 __42-[JournalNutritionViewController setDate:]_block_invoke + 184
12 Euco 0x0000000100067f7e __57+[Day(ModelFunctions) read:withType:withSuccess:failure:]_block_invoke + 142
13 Euco 0x0000000100200b3b __66-[RKObjectRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke242 + 91
14 libdispatch.dylib 0x0000000103e50851 _dispatch_call_block_and_release + 12
15 libdispatch.dylib 0x0000000103e6372d _dispatch_client_callout + 8
16 libdispatch.dylib 0x0000000103e533fc _dispatch_main_queue_callback_4CF + 354
17 CoreFoundation 0x00000001038ff289 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
18 CoreFoundation 0x000000010384c854 __CFRunLoopRun + 1764
19 CoreFoundation 0x000000010384bd83 CFRunLoopRunSpecific + 467
20 GraphicsServices 0x0000000104af0f04 GSEventRunModal + 161
21 UIKit 0x00000001022d7e33 UIApplicationMain + 1010
22 Euco 0x0000000100063113 main + 115
23 libdyld.dylib 0x00000001040b45fd start + 1
24 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
When I add an exception breakpoint, it stops here before crashing:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.day.nutrition_plan.meal_goals.count
}
When it breaks there, if I run po self.day in the console, it returns <FoodEntry: 0x10ab5ff20> so it is somehow thinking the Day object is a FoodEntry object.
From your description your orphan block looks fine. It verifies the URL that is being processed so should be auctioned at the appropriate times.
This code:
self.day = (Day *)mappingResult.firstObject;
is a risk in a number of cases because you can't always be sure what the first object in the mapping result will be. If:
You have multiple mapped objects (nested)
You have multiple response descriptors (which leads to 1.)
then the mapping result should be queried as a dictionary and you should check the contents before casting them to what you hope they are. Basically never access the mapping result as an array.
For some reason, I randomly sometimes get this crash.
Fatal Exception: NSInternalInconsistencyException
Cannot determine hasNextPage: paginator is not loaded.
Thread : Fatal Exception: NSInternalInconsistencyException
0 CoreFoundation 0x309a1f4b __exceptionPreprocess + 130
1 libobjc.A.dylib 0x3b1386af objc_exception_throw + 38
2 CoreFoundation 0x309a1e25 +[NSException raise:format:]
3 Foundation 0x31349fe3 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 90
4 Poka 0x004f0f71 -[RKPaginator hasNextPage] (RKPaginator.m:151)
5 Poka 0x00289a41 __66-[PokaLocationContentManagerSingleton fetchLatestPlantsWithCount:]_block_invoke (PokaLocationContentManagerSingleton.m:345)
6 Poka 0x004f2495 __24-[RKPaginator loadPage:]_block_invoke157 (RKPaginator.m:231)
7 Poka 0x004e9355 __66-[RKObjectRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke244 (RKObjectRequestOperation.m:477)
8 libdispatch.dylib 0x3b61bd1b _dispatch_call_block_and_release + 10
9 libdispatch.dylib 0x3b61bd07 _dispatch_client_callout + 22
10 libdispatch.dylib 0x3b62278d _dispatch_main_queue_callback_4CF$VARIANT$mp + 268
11 CoreFoundation 0x3096c819 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 8
12 CoreFoundation 0x3096b0ed __CFRunLoopRun + 1300
13 CoreFoundation 0x308d5c27 CFRunLoopRunSpecific + 522
14 CoreFoundation 0x308d5a0b CFRunLoopRunInMode + 106
15 GraphicsServices 0x355c9283 GSEventRunModal + 138
16 UIKit 0x33179049 UIApplicationMain + 1136
17 Poka 0x0006df95 main (main.m:17)
18 libdyld.dylib 0x3b640ab7 start + 2
I am loading the Paginator like this:
- (void)fetchLatestPlantsWithCount:(NSNumber *)count
{
RKObjectManager *objectManager = [RKObjectManager sharedManager];
NSString *requestString = [NSString stringWithFormat:#"/api/rest/plants/?count=%#&limit=:perPage&offset=:offset", count];
NSDictionary *parameters = nil;
if(_dateFilterLastModifiedAppend)
parameters = [[NSDictionary alloc]initWithObjectsAndKeys:_dateFilterLastModifiedAppend, #"last_modified_date__gte", nil];
RKPaginator *paginator = [objectManager paginatorWithPathPattern:requestString parameters:parameters];
paginator.perPage = API_PER_PAGE_LIMIT;
[ZAActivityBar showWithStatus:[NSString stringWithFormat:NSLocalizedStringFromTable(#"Downloading latest plants: %# remaining", #"PokaLocalizable", nil), count]];
[paginator setCompletionBlockWithSuccess:^(RKPaginator *paginator, NSArray *objects, NSUInteger page) {
if([paginator hasNextPage])
{
[ZAActivityBar showWithStatus:[NSString stringWithFormat:NSLocalizedStringFromTable(#"Downloading latest plants: %# remaining", #"PokaLocalizable", nil), [NSNumber numberWithInt:([count integerValue] - paginator.offset)]]];
[paginator loadNextPage];
}
else
{
[self fetchLatestProductionLinesCount];
}
} failure:^(RKPaginator *paginator, NSError *error) {
[self fetchLatestProductionLinesCount];
}];
[paginator loadPage:1];
}
Finally, I added some code to RestKit in order to load the paginator. I don't think it is the problem though.
- (RKPaginator *)paginatorWithPathPattern:(NSString *)pathPattern parameters:(NSDictionary *)parameters
{
NSAssert(self.paginationMapping, #"Cannot instantiate a paginator when `paginationMapping` is nil.");
NSMutableURLRequest *request = [self requestWithMethod:#"GET" path:pathPattern parameters:parameters];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:self.responseDescriptors];
#ifdef _COREDATADEFINES_H
paginator.managedObjectContext = self.managedObjectStore.mainQueueManagedObjectContext;
paginator.managedObjectCache = self.managedObjectStore.managedObjectCache;
paginator.fetchRequestBlocks = self.fetchRequestBlocks;
#endif
paginator.operationQueue = self.operationQueue;
Class HTTPOperationClass = [self requestOperationClassForRequest:request fromRegisteredClasses:self.registeredHTTPRequestOperationClasses];
if (HTTPOperationClass) [paginator setHTTPOperationClass:HTTPOperationClass];
return paginator;
}
The only difference is that I pass some parameters to it.
The thing I don't understand is that I load other objects, WITH that same code with the only difference being the type of objects I am downloading. I execute almost that same code right before executing this one, and it works perfectly fine. Hence, my question as to I am confused...
Some more information:
It says the object count is 1, that page is 1, but apparently it is not loaded?
Note that I call the paginator multiple times within the same page. I do the paginator for one type of objects... once it is done I do it for another one... and so on.
All pull requests that I mentioned before were merged already to master. So just use the newest version.
I found an issue and fixed it if you are interested. I posted Pull Request on RestKit github page
https://github.com/RestKit/RestKit/pull/2156
I would recommend to use my fork on branch inventorum where I also cherry picked malloc error fix:
https://github.com/bimusiek/RestKit/commits/inventorum
I'm curious to know why I'm receiving an exception on this code and as to what this exception means. When I remove the for loop, as indicated below, it works fine. When I include it, I get an exception.
-(void) loadVenues {
NSString *latLon = #"34.0500, -118.2500"; // approximate latLon of The Mothership (a.k.a Apple headquarters)
NSString *clientID = kCLIENTID;
NSString *clientSecret = kCLIENTSECRET;
//34.0500° N, 118.2500
NSDictionary *queryParams = #{#"ll" : latLon,
#"client_id" : clientID,
#"client_secret" : clientSecret,
#"categoryId" : #"4bf58dd8d48988d1e0931735",
#"v" : #"20140118"};
[[RKObjectManager sharedManager] getObjectsAtPath:#"/v2/venues/search"
parameters:queryParams
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
_venues = mappingResult.array;
NSMutableArray *temp = [(NSArray*)_venues mutableCopy];
for (int i =0; i < _venues.count; i++)
{
NSUInteger index = 0;
for (int j = 0; j <_venues.count; j++)
{
//((MyObjectType *) [myArray objectAtIndex:0]).intProperty = 12345;
if(((Venue *) [temp objectAtIndex:index]).location.distance > 0)
{
Venue *holder= [temp objectAtIndex:index];
[temp removeObjectAtIndex:index];
NSUInteger indexer = index +1;
[temp addObject:[temp objectAtIndex:indexer]];
//replace a with a+1
[temp replaceObjectAtIndex:indexer withObject:holder];
//[temp addObject:holder atIndex: index+1];
//a[i+1]=holder;
index++;
}
else {index++;}
}
}
_venues = temp;
[self.tableView reloadData];
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"What do you mean by 'there is no coffee?': %#", error);
}
];
}
I'm getting an exception at this line:
[temp addObject:[temp objectAtIndex:indexer]];
And I'm not sure why.
Here is the error:
2014-07-02 21:43:12.536 CoffeeKit[63581:60b] I restkit:RKLog.m:33 RestKit logging initialized...
2014-07-02 21:43:12.655 CoffeeKit[63581:60b] I restkit.network:RKObjectRequestOperation.m:150 GET 'https://api.foursquare.com/v2/venues/search?categoryId=4bf58dd8d48988d1e0931735&client_id=ZE5VJOPEO1PP3NDFVCM3O2ZUXWDDJRB20XDDGH3OETBKOVZB&client_secret=5LGY2CEASBQZQS5P0LYFICWDKMDOHJJ00F3G24LT4J4DX4X3&ll=34.0500%2C%20-118.2500&v=20140118'
2014-07-02 21:43:13.085 CoffeeKit[63581:f03] I restkit.network:RKObjectRequestOperation.m:220 GET 'https://api.foursquare.com/v2/venues/search?categoryId=4bf58dd8d48988d1e0931735&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&ll=34.0500%2C%20-118.2500&v=20140118' (200 OK / 30 objects) [request=0.4171s mapping=0.0128s total=0.4486s]
2014-07-02 21:43:13.087 CoffeeKit[63581:60b] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 29 beyond bounds [0 .. 28]'
*** First throw call stack:
(
0 CoreFoundation 0x00000001023a0495 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001020ff99e objc_exception_throw + 43
2 CoreFoundation 0x0000000102346745 -[__NSArrayM objectAtIndex:] + 213
3 CoffeeKit 0x0000000100002efa __34-[MasterViewController loadVenues]_block_invoke + 602
4 CoffeeKit 0x000000010009310b __66-[RKObjectRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke244 + 91
5 libdispatch.dylib 0x0000000102c9a851 _dispatch_call_block_and_release + 12
6 libdispatch.dylib 0x0000000102cad72d _dispatch_client_callout + 8
7 libdispatch.dylib 0x0000000102c9d3fc _dispatch_main_queue_callback_4CF + 354
8 CoreFoundation 0x00000001023fe289 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
9 CoreFoundation 0x000000010234b854 __CFRunLoopRun + 1764
10 CoreFoundation 0x000000010234ad83 CFRunLoopRunSpecific + 467
11 GraphicsServices 0x00000001033e2f04 GSEventRunModal + 161
12 UIKit 0x0000000100cace33 UIApplicationMain + 1010
13 CoffeeKit 0x0000000100003733 main + 115
14 libdyld.dylib 0x0000000102efe5fd start + 1
15 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
As you can see from your stack, your error is occurring because you attempt to access the object at index 29, which is outside of the array's bounds:
* -[__NSArrayM objectAtIndex:]: index 29 beyond bounds [0 .. 28]
In your case, it's probably arising from this line:
NSUInteger indexer = index +1;
[temp addObject:[temp objectAtIndex:indexer]];
Which I'm assuming you're using to get the value of the next object. Once the array reaches the 28th object, however, you attempt to access the imaginary 29th object.
Bottom line: refactor your code so that you only access objects that exist.
You are getting out of bounds by accessing the NEXT element in the array, 2 things. you can directly use 'j' to access the element (instead of index, so u dont have to increment it urself) and you can change your for from
for (int j = 0; j <_venues.count; j++)
to
for (int j = 0; j <_venues.count-1; j++)
By the way if all you need is sorting, NSMutableArray offers many options:
Rearranging Content
– exchangeObjectAtIndex:withObjectAtIndex:
– sortUsingDescriptors:
– sortUsingComparator:
– sortWithOptions:usingComparator:
– sortUsingFunction:context:
– sortUsingSelector:
I have a bit of code in my application that generates a Core Data Model and populates it with a set of NSEntityDescriptions. Each of these entity descriptions then have an arbitrary number of NSPropertyDescriptions allocated for them. These properties are a combination of NSAttributeDescriptions and NSRelationshipDescriptions. All relationships are matched with an existing relationship and they are set as inverse of one another using setInverseRelationship:.
The attribute properties work fine, and to-many relationships work fine; I have tested that thoroughly. The issue seems to be with NSRelationshipDescriptions that have a maxCount value of 1, meaning the property description returns a isToMany value of NO. When the inverseRelationship property is set for these type of relationship, Core Data crashes when I try to save any object that utilizes that relationship with the error:
2013-11-09 11:17:15.068 Directory[1344:5c03] -[NSManagedObject count]: unrecognized selector sent to instance 0x9643820
2013-11-09 11:17:15.074 Directory[1344:5c03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObject count]: unrecognized selector sent to instance 0x9643820'
*** First throw call stack:
(
0 CoreFoundation 0x01f9f5e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x01d228b6 objc_exception_throw + 44
2 CoreFoundation 0x0203c903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
3 CoreFoundation 0x01f8f90b ___forwarding___ + 1019
4 CoreFoundation 0x01f8f4ee _CF_forwarding_prep_0 + 14
5 CoreData 0x0083c128 -[NSSQLCore _knownOrderKeyForObject:from:inverseToMany:] + 200
6 CoreData 0x00773080 -[NSSQLCore _populateRowForOp:withObject:] + 1120
7 CoreData 0x00789157 -[NSSQLCore recordValuesForInsertedObject:] + 71
8 CoreData 0x00771e8d -[NSSQLCore recordChangesInContext:] + 685
9 CoreData 0x00770c55 -[NSSQLCore saveChanges:] + 565
10 CoreData 0x0073d88c -[NSSQLCore executeRequest:withContext:error:] + 412
11 CoreData 0x0073d380 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 4704
12 CoreData 0x00769ffc -[NSManagedObjectContext save:] + 764
13 Directory 0x0002f2bf -[ETDatabaseController save] + 111
14 Directory 0x0002ba9c -[ETDataLoader performImportWithData:] + 10284
The insinuation I am gathering from this is it is considering the inverse relationship to be a to-many relationship when that is not the case. According to my assertions, what I know about each of my relationships is:
relationDescription.inverseRelationship != nil
[relationDescription.inverseRelationship.inverseRelationship isEqual:relationDescription]
I have tested this by creating the model and populating it with a small set of sample data. Currently, objects that have any sort of attributes, to-many relationships (with/without inverse), and to-one relationship (without inverse) work consistently. The issues comes when I try to have a to-one relationship with an inverse relationship.
This seems a bit convoluted so let me know if I need to clarify anything better. Thanks!
Edit 1:
The relationship creation is done in two steps, first it creates all the relationships, then it establishes the inverse of each relationship by using a lookup.
NSRelationshipDescription *description = [[NSRelationshipDescription alloc] init];
[description setName:self.name];
[description setDestinationEntity:entity];
[description setMaxCount:(isToMany ? 0 : 1)];
[description setMinCount:0];
[description setOrdered:YES]; // See you in a minute
later...
NSEntityDescription *inverseEntity = newRelationship.destinationEntity;
NSRelationshipDescription *inverseRelationDescription = [inverseEntity relationshipsByName][inverse.name];
if (inverseRelationDescription) {
inverseRelationDescription.inverseRelationship = newRelationship;
newRelationship.inverseRelationship = inverseRelationDescription;
} else if ([inverse.name isEqualToString:relation.name]) {
newRelationship.inverseRelationship = newRelationship;
}
Well, I guess writing Edit 1 made something click. So from what it looks like, if you call setOrdered: on a NSRelationDescription that is meant to be a to-one relationship, the internals of Core Data automatically considers it a to-many relationship, despite the conflict with the maxCount being one.
I fixed this by changing the creation code for the relationship from:
NSRelationshipDescription *description = [[NSRelationshipDescription alloc] init];
[description setName:self.name];
[description setDestinationEntity:entity];
[description setMaxCount:(isToMany ? 0 : 1)];
[description setMinCount:0];
[description setOrdered:YES];
to:
NSRelationshipDescription *description = [[NSRelationshipDescription alloc] init];
[description setName:self.name];
[description setDestinationEntity:entity];
[description setMaxCount:(isToMany ? 0 : 1)];
[description setMinCount:0];
if (isToMany)
[description setOrdered:YES];