@@ -115,6 +115,7 @@ - (void)visitMapping:(RKMapping *)mapping atKeyPath:(NSString *)keyPath
115
115
NSMutableArray *newValue = [[NSMutableArray alloc ] initWithCapacity: [value count ]];
116
116
for (__strong id object in value) {
117
117
if ([object isKindOfClass: [NSManagedObject class ]]) {
118
+ if (![object managedObjectContext ]) continue ; // Object was deleted
118
119
object = [managedObjectContext existingObjectWithID: [object objectID ] error: &error];
119
120
NSCAssert (object, @" Failed to find existing object with ID %@ in context %@ : %@ " , [object objectID ], managedObjectContext, error);
120
121
}
@@ -127,6 +128,7 @@ - (void)visitMapping:(RKMapping *)mapping atKeyPath:(NSString *)keyPath
127
128
NSMutableSet *newValue = [[NSMutableSet alloc ] initWithCapacity: [value count ]];
128
129
for (__strong id object in value) {
129
130
if ([object isKindOfClass: [NSManagedObject class ]]) {
131
+ if (![object managedObjectContext ]) continue ; // Object was deleted
130
132
object = [managedObjectContext existingObjectWithID: [object objectID ] error: &error];
131
133
NSCAssert (object, @" Failed to find existing object with ID %@ in context %@ : %@ " , [object objectID ], managedObjectContext, error);
132
134
}
@@ -139,15 +141,21 @@ - (void)visitMapping:(RKMapping *)mapping atKeyPath:(NSString *)keyPath
139
141
NSMutableOrderedSet *newValue = [NSMutableOrderedSet orderedSet ];
140
142
[(NSOrderedSet *)value enumerateObjectsUsingBlock: ^(id object, NSUInteger index, BOOL *stop) {
141
143
if ([object isKindOfClass: [NSManagedObject class ]]) {
142
- object = [managedObjectContext existingObjectWithID: [object objectID ] error: &error];
143
- NSCAssert (object, @" Failed to find existing object with ID %@ in context %@ : %@ " , [object objectID ], managedObjectContext, error);
144
+ if ([object managedObjectContext ]) {
145
+ object = [managedObjectContext existingObjectWithID: [object objectID ] error: &error];
146
+ NSCAssert (object, @" Failed to find existing object with ID %@ in context %@ : %@ " , [object objectID ], managedObjectContext, error);
147
+ } else {
148
+ // Object was deleted
149
+ object = nil ;
150
+ }
144
151
}
145
152
146
- [newValue setObject: object atIndex: index];
153
+ if (object) [newValue setObject: object atIndex: index];
147
154
}];
148
155
value = (isMutable) ? newValue : [newValue copy ];
149
156
} else if ([value isKindOfClass: [NSManagedObject class ]]) {
150
- value = [managedObjectContext existingObjectWithID: [value objectID ] error: &error];
157
+ // Object becomes nil if deleted
158
+ value = [value managedObjectContext ] ? [managedObjectContext existingObjectWithID: [value objectID ] error: &error] : nil ;
151
159
NSCAssert (value, @" Failed to find existing object with ID %@ in context %@ : %@ " , [value objectID ], managedObjectContext, error);
152
160
}
153
161
@@ -330,7 +338,7 @@ - (NSSet *)localObjectsFromFetchRequestsMatchingRequestURL:(NSError **)error
330
338
return localObjects;
331
339
}
332
340
333
- - (BOOL )deleteLocalObjectsMissingFromMappingResult : (RKMappingResult *)result error : (NSError **)error
341
+ - (BOOL )deleteLocalObjectsMissingFromMappingResult : (RKMappingResult *)result atKeyPaths : ( NSSet *) keyPaths error : (NSError **)error
334
342
{
335
343
if (! self.deletesOrphanedObjects ) {
336
344
RKLogDebug (@" Skipping deletion of orphaned objects: deletesOrphanedObjects=NO" );
@@ -342,11 +350,26 @@ - (BOOL)deleteLocalObjectsMissingFromMappingResult:(RKMappingResult *)result err
342
350
return YES ;
343
351
}
344
352
345
- NSArray *results = [result array ];
353
+ // Build an aggregate collection of all the managed objects in the mapping result
354
+ NSMutableSet *managedObjectsInMappingResult = [NSMutableSet set ];
355
+ NSDictionary *mappingResultDictionary = result.dictionary ;
356
+ for (NSString *keyPath in keyPaths) {
357
+ id managedObjects = [mappingResultDictionary valueForKeyPath: keyPath];
358
+ if ([managedObjects isKindOfClass: [NSManagedObject class ]]) {
359
+ [managedObjectsInMappingResult addObject: managedObjects];
360
+ } else if ([managedObjects isKindOfClass: [NSSet class ]]) {
361
+ [managedObjectsInMappingResult unionSet: managedObjects];
362
+ } else if ([managedObjects isKindOfClass: [NSArray class ]]) {
363
+ [managedObjectsInMappingResult addObjectsFromArray: managedObjects];
364
+ } else {
365
+ [NSException raise: NSInternalInconsistencyException format: @" Unexpected object type '%@ ' encountered at keyPath '%@ ': Expected an `NSManagedObject`, `NSArray`, or `NSSet`." , [managedObjects class ], keyPath];
366
+ }
367
+ }
368
+
346
369
NSSet *localObjects = [self localObjectsFromFetchRequestsMatchingRequestURL: error];
347
370
if (! localObjects) return NO ;
348
371
for (id object in localObjects) {
349
- if (NO == [results containsObject: object]) {
372
+ if (NO == [managedObjectsInMappingResult containsObject: object]) {
350
373
RKLogDebug (@" Deleting orphaned object %@ : not found in result set and expected at this URL" , object);
351
374
[self .privateContext performBlockAndWait: ^{
352
375
[self .privateContext deleteObject: object];
@@ -407,14 +430,18 @@ - (void)willFinish
407
430
BOOL success;
408
431
NSError *error = nil ;
409
432
433
+ // Construct a set of key paths to all of the managed objects in the mapping result
434
+ RKNestedManagedObjectKeyPathMappingGraphVisitor *visitor = [[RKNestedManagedObjectKeyPathMappingGraphVisitor alloc ] initWithResponseDescriptors: self .responseDescriptors];
435
+ NSSet *managedObjectMappingResultKeyPaths = visitor.keyPaths ;
436
+
410
437
// Handle any cleanup
411
438
success = [self deleteTargetObjectIfAppropriate: &error];
412
439
if (! success) {
413
440
self.error = error;
414
441
return ;
415
442
}
416
443
417
- success = [self deleteLocalObjectsMissingFromMappingResult: self .mappingResult error: &error];
444
+ success = [self deleteLocalObjectsMissingFromMappingResult: self .mappingResult atKeyPaths: managedObjectMappingResultKeyPaths error: &error];
418
445
if (! success) {
419
446
self.error = error;
420
447
return ;
@@ -431,8 +458,7 @@ - (void)willFinish
431
458
432
459
// Refetch all managed objects nested at key paths within the results dictionary before returning
433
460
if (self.mappingResult ) {
434
- RKNestedManagedObjectKeyPathMappingGraphVisitor *visitor = [[RKNestedManagedObjectKeyPathMappingGraphVisitor alloc ] initWithResponseDescriptors: self .responseDescriptors];
435
- NSDictionary *resultsDictionaryFromOriginalContext = RKDictionaryFromDictionaryWithManagedObjectsAtKeyPathsRefetchedInContext ([self .mappingResult dictionary ], visitor.keyPaths , self.managedObjectContext );
461
+ NSDictionary *resultsDictionaryFromOriginalContext = RKDictionaryFromDictionaryWithManagedObjectsAtKeyPathsRefetchedInContext ([self .mappingResult dictionary ], managedObjectMappingResultKeyPaths, self.managedObjectContext );
436
462
self.mappingResult = [[RKMappingResult alloc ] initWithDictionary: resultsDictionaryFromOriginalContext];
437
463
}
438
464
}
0 commit comments