36
36
37
37
extern NSString * const RKObjectMappingNestingAttributeKeyName;
38
38
39
- static char kRKManagedObjectMappingOperationDataSourceAssociatedObjectKey ;
39
+ static void *RKManagedObjectMappingOperationDataSourceAssociatedObjectKey = &RKManagedObjectMappingOperationDataSourceAssociatedObjectKey ;
40
40
41
- id RKTransformedValueWithClass (id value, Class destinationType, NSValueTransformer *dateToStringValueTransformer);
42
41
NSArray *RKApplyNestingAttributeValueToMappings (NSString *attributeName, id value, NSArray *propertyMappings);
43
42
44
- // Return YES if the entity is identified by an attribute that acts as the nesting key in the source representation
45
- static BOOL RKEntityMappingIsIdentifiedByNestingAttribute (RKEntityMapping *entityMapping)
46
- {
47
- for (NSAttributeDescription *attribute in [entityMapping identificationAttributes ]) {
48
- RKAttributeMapping *attributeMapping = [[entityMapping propertyMappingsByDestinationKeyPath ] objectForKey: [attribute name ]];
49
- if ([attributeMapping.sourceKeyPath isEqualToString: RKObjectMappingNestingAttributeKeyName]) {
50
- return YES ;
51
- }
52
- }
53
-
54
- return NO ;
55
- }
56
-
57
43
static id RKValueForAttributeMappingInRepresentation (RKAttributeMapping *attributeMapping, NSDictionary *representation)
58
44
{
59
45
if ([attributeMapping.sourceKeyPath isEqualToString: RKObjectMappingNestingAttributeKeyName]) {
@@ -81,16 +67,15 @@ static id RKValueForAttributeMappingInRepresentation(RKAttributeMapping *attribu
81
67
{
82
68
NSCParameterAssert (entityMapping);
83
69
NSCAssert ([representation isKindOfClass: [NSDictionary class ]], @" Expected a dictionary representation" );
84
-
85
- RKDateToStringValueTransformer *dateToStringTransformer = [[RKDateToStringValueTransformer alloc ] initWithDateToStringFormatter: entityMapping.preferredDateFormatter
86
- stringToDateFormatters: entityMapping.dateFormatters];
87
70
NSArray *attributeMappings = entityMapping.attributeMappings ;
88
-
71
+ __block NSError *error = nil ;
72
+
89
73
// If the representation is mapped with a nesting attribute, we must apply the nesting value to the representation before constructing the identification attributes
90
74
RKAttributeMapping *nestingAttributeMapping = [[entityMapping propertyMappingsBySourceKeyPath ] objectForKey: RKObjectMappingNestingAttributeKeyName];
91
75
if (nestingAttributeMapping) {
92
76
Class attributeClass = [entityMapping classForProperty: nestingAttributeMapping.destinationKeyPath];
93
- id attributeValue = RKTransformedValueWithClass ([[representation allKeys ] lastObject ], attributeClass, dateToStringTransformer);
77
+ id attributeValue = nil ;
78
+ [entityMapping.valueTransformer transformValue: [[representation allKeys ] lastObject ] toValue: &attributeValue ofClass: attributeClass error: &error];
94
79
attributeMappings = RKApplyNestingAttributeValueToMappings (nestingAttributeMapping.destinationKeyPath , attributeValue, attributeMappings);
95
80
}
96
81
@@ -100,7 +85,8 @@ static id RKValueForAttributeMappingInRepresentation(RKAttributeMapping *attribu
100
85
RKAttributeMapping *attributeMapping = RKAttributeMappingForNameInMappings ([attribute name ], attributeMappings);
101
86
Class attributeClass = [entityMapping classForProperty: [attribute name ]];
102
87
id sourceValue = RKValueForAttributeMappingInRepresentation (attributeMapping, representation);
103
- id attributeValue = RKTransformedValueWithClass (sourceValue, attributeClass, dateToStringTransformer);
88
+ id attributeValue = nil ;
89
+ if (sourceValue) [entityMapping.valueTransformer transformValue: sourceValue toValue: &attributeValue ofClass: attributeClass error: &error];
104
90
[entityIdentifierAttributes setObject: attributeValue ?: [NSNull null ] forKey: [attribute name ]];
105
91
}];
106
92
@@ -253,7 +239,7 @@ - (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRep
253
239
id existingObjectsOfRelationship = identificationAttributes ? [mappingOperation.destinationObject valueForKeyPath: relationship.destinationKeyPath] : RKMutableCollectionValueWithObjectForKeyPath (mappingOperation.destinationObject , relationship.destinationKeyPath );
254
240
if (existingObjectsOfRelationship && !RKObjectIsCollection (existingObjectsOfRelationship)) existingObjectsOfRelationship = @[ existingObjectsOfRelationship ];
255
241
for (NSManagedObject *existingObject in existingObjectsOfRelationship) {
256
- if (! identificationAttributes) {
242
+ if (! identificationAttributes && ![existingObject isDeleted ] ) {
257
243
managedObject = existingObject;
258
244
[existingObjectsOfRelationship removeObject: managedObject];
259
245
break ;
@@ -341,9 +327,10 @@ - (BOOL)commitChangesForMappingOperation:(RKMappingOperation *)mappingOperation
341
327
// Add a dependency on the parent operation. If we are being mapped as part of a relationship, then the assignment of the mapped object to a parent may well fulfill the validation requirements. This ensures that the relationship mapping has completed before we evaluate the object for deletion.
342
328
if (self.parentOperation ) [deletionOperation addDependency: self .parentOperation];
343
329
330
+ RKRelationshipConnectionOperation *connectionOperation = nil ;
344
331
if ([connections count ]) {
345
- RKRelationshipConnectionOperation *operation = [[RKRelationshipConnectionOperation alloc ] initWithManagedObject: mappingOperation.destinationObject connections: connections managedObjectCache: self .managedObjectCache];
346
- [operation setConnectionBlock: ^(RKRelationshipConnectionOperation *operation, RKConnectionDescription *connection, id connectedValue) {
332
+ connectionOperation = [[RKRelationshipConnectionOperation alloc ] initWithManagedObject: mappingOperation.destinationObject connections: connections managedObjectCache: self .managedObjectCache];
333
+ [connectionOperation setConnectionBlock: ^(RKRelationshipConnectionOperation *operation, RKConnectionDescription *connection, id connectedValue) {
347
334
if (connectedValue) {
348
335
if ([mappingOperation.delegate respondsToSelector: @selector (mappingOperation:didConnectRelationship:toValue:usingConnection: )]) {
349
336
[mappingOperation.delegate mappingOperation: mappingOperation didConnectRelationship: connection.relationship toValue: connectedValue usingConnection: connection];
@@ -355,34 +342,35 @@ - (BOOL)commitChangesForMappingOperation:(RKMappingOperation *)mappingOperation
355
342
}
356
343
}];
357
344
358
- if (self.parentOperation ) [operation addDependency: self .parentOperation];
359
- [deletionOperation addDependency: operation ];
360
- [operationQueue addOperation: operation ];
361
- RKLogTrace (@" Enqueued %@ dependent upon parent operation %@ to operation queue %@ " , operation , self.parentOperation , operationQueue);
345
+ if (self.parentOperation ) [connectionOperation addDependency: self .parentOperation];
346
+ [deletionOperation addDependency: connectionOperation ];
347
+ [operationQueue addOperation: connectionOperation ];
348
+ RKLogTrace (@" Enqueued %@ dependent upon parent operation %@ to operation queue %@ " , connectionOperation , self.parentOperation , operationQueue);
362
349
}
363
350
364
351
// Enqueue our deletion operation for execution after all the connections
365
352
[operationQueue addOperation: deletionOperation];
366
353
367
354
// Handle tombstone deletion by predicate
368
355
if ([(RKEntityMapping *)mappingOperation.objectMapping deletionPredicate ]) {
369
- RKManagedObjectDeletionOperation *deletionOperation = nil ;
370
- if (self.parentOperation ) {
356
+ RKManagedObjectDeletionOperation *predicateDeletionOperation = nil ;
357
+ // Attach a deletion operation for execution after the parent operation completes
358
+ predicateDeletionOperation = (RKManagedObjectDeletionOperation *)objc_getAssociatedObject (self.parentOperation , RKManagedObjectMappingOperationDataSourceAssociatedObjectKey);
359
+ if (! predicateDeletionOperation) {
360
+ predicateDeletionOperation = [[RKManagedObjectDeletionOperation alloc ] initWithManagedObjectContext: self .managedObjectContext];
361
+
371
362
// Attach a deletion operation for execution after the parent operation completes
372
- deletionOperation = (RKManagedObjectDeletionOperation *)objc_getAssociatedObject (self.parentOperation , &kRKManagedObjectMappingOperationDataSourceAssociatedObjectKey );
373
- if (! deletionOperation) {
374
- deletionOperation = [[RKManagedObjectDeletionOperation alloc ] initWithManagedObjectContext: self .managedObjectContext];
375
- objc_setAssociatedObject (self.parentOperation , &kRKManagedObjectMappingOperationDataSourceAssociatedObjectKey , deletionOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC );
376
- [deletionOperation addDependency: self .parentOperation];
377
- NSOperationQueue *operationQueue = self.operationQueue ?: [NSOperationQueue currentQueue ];
378
- [operationQueue addOperation: deletionOperation];
363
+ if (self.parentOperation ) {
364
+ objc_setAssociatedObject (self.parentOperation , RKManagedObjectMappingOperationDataSourceAssociatedObjectKey, predicateDeletionOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC );
365
+ [predicateDeletionOperation addDependency: self .parentOperation];
379
366
}
380
- [deletionOperation addEntityMapping: (RKEntityMapping *)mappingOperation.objectMapping];
381
- } else {
382
- deletionOperation = [[RKManagedObjectDeletionOperation alloc ] initWithManagedObjectContext: self .managedObjectContext ];
383
- [deletionOperation addEntityMapping: (RKEntityMapping *)mappingOperation.objectMapping];
384
- [deletionOperation start ];
367
+
368
+ // Ensure predicate deletion executes after any connections have been established
369
+ if (connectionOperation) [predicateDeletionOperation addDependency: connectionOperation ];
370
+
371
+ [operationQueue addOperation: predicateDeletionOperation ];
385
372
}
373
+ [predicateDeletionOperation addEntityMapping: (RKEntityMapping *)mappingOperation.objectMapping];
386
374
}
387
375
}
388
376
@@ -423,7 +411,7 @@ - (void)updateCacheWithChangesFromContextWillSaveNotification:(NSNotification *)
423
411
- (BOOL )mappingOperation : (RKMappingOperation *)mappingOperation deleteExistingValueOfRelationshipWithMapping : (RKRelationshipMapping *)relationshipMapping error : (NSError **)error
424
412
{
425
413
// Validate the assignment policy
426
- if (! relationshipMapping.assignmentPolicy = = RKReplaceAssignmentPolicy) {
414
+ if (relationshipMapping.assignmentPolicy ! = RKReplaceAssignmentPolicy) {
427
415
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : @" Unable to satisfy deletion request: Relationship mapping was expected to have an assignment policy of `RKReplaceAssignmentPolicy`, but did not." };
428
416
NSError *localError = [NSError errorWithDomain: RKErrorDomain code: RKMappingErrorInvalidAssignmentPolicy userInfo: userInfo];
429
417
if (error) *error = localError;
@@ -466,10 +454,12 @@ - (BOOL)mappingOperationShouldSkipPropertyMapping:(RKMappingOperation *)mappingO
466
454
if (! [currentValue respondsToSelector: @selector (compare: )]) return NO ;
467
455
468
456
RKPropertyMapping *propertyMappingForModificationKey = [[(RKEntityMapping *)mappingOperation.mapping propertyMappingsByDestinationKeyPath ] objectForKey: modificationKey];
469
- id rawValue = [[mappingOperation sourceObject ] valueForKeyPath: propertyMappingForModificationKey.sourceKeyPath];
470
- RKDateToStringValueTransformer *transformer = [[RKDateToStringValueTransformer alloc ] initWithDateToStringFormatter: entityMapping.preferredDateFormatter stringToDateFormatters: entityMapping.dateFormatters];
457
+ id rawValue = [[mappingOperation sourceObject ] valueForKeyPath: propertyMappingForModificationKey.sourceKeyPath];
471
458
Class attributeClass = [entityMapping classForProperty: propertyMappingForModificationKey.destinationKeyPath];
472
- id transformedValue = RKTransformedValueWithClass (rawValue, attributeClass, transformer);
459
+
460
+ id transformedValue = nil ;
461
+ NSError *error = nil ;
462
+ [entityMapping.valueTransformer transformValue: rawValue toValue: &transformedValue ofClass: attributeClass error: &error];
473
463
if (! transformedValue) return NO ;
474
464
475
465
if ([currentValue isKindOfClass: [NSString class ]]) {
0 commit comments