// // RKRelationshipConnectionOperation.m // RestKit // // Created by Blake Watters on 7/12/12. // Copyright (c) 2012 RestKit. All rights reserved. // #import #import "RKRelationshipConnectionOperation.h" #import "RKEntityMapping.h" #import "RKLog.h" #import "RKManagedObjectCaching.h" #import "RKDynamicMappingMatcher.h" @interface RKRelationshipConnectionOperation () @property (nonatomic, strong, readwrite) NSManagedObject *managedObject; @property (nonatomic, strong, readwrite) RKConnectionMapping *connectionMapping; @property (nonatomic, strong, readwrite) id managedObjectCache; // Helpers @property (weak, nonatomic, readonly) NSManagedObjectContext *managedObjectContext; @property (weak, nonatomic, readonly) RKEntityMapping *entityMapping; @end @implementation RKRelationshipConnectionOperation @synthesize managedObject = _managedObject; @synthesize connectionMapping = _connectionMapping; @synthesize managedObjectCache = _managedObjectCache; - (id)initWithManagedObject:(NSManagedObject *)managedObject connectionMapping:(RKConnectionMapping *)connectionMapping managedObjectCache:(id)managedObjectCache { self = [self init]; if (self) { self.managedObject = managedObject; self.connectionMapping = connectionMapping; self.managedObjectCache = managedObjectCache; } return self; } - (RKEntityMapping *)entityMapping { return (RKEntityMapping *)self.connectionMapping.mapping; } - (NSManagedObjectContext *)managedObjectContext { return self.managedObject.managedObjectContext; } - (NSManagedObject *)findOneConnectedWithSourceValue:(id)sourceValue { return [self.managedObjectCache findInstanceOfEntity:self.entityMapping.entity withPrimaryKeyAttribute:self.connectionMapping.destinationKeyPath value:sourceValue inManagedObjectContext:self.managedObjectContext]; } - (NSMutableSet *)findAllConnectedWithSourceValue:(id)sourceValue { NSMutableSet *result = [NSMutableSet set]; id values = nil; if ([sourceValue conformsToProtocol:@protocol(NSFastEnumeration)]) { values = sourceValue; } else { values = [NSArray arrayWithObject:sourceValue]; } for (id value in values) { NSArray *objects = [self.managedObjectCache findInstancesOfEntity:self.entityMapping.entity withPrimaryKeyAttribute:self.connectionMapping.destinationKeyPath value:value inManagedObjectContext:self.managedObjectContext]; [result addObjectsFromArray:objects]; } return result; } - (BOOL)isToMany { NSEntityDescription *entity = [self.managedObject entity]; NSDictionary *relationships = [entity relationshipsByName]; NSRelationshipDescription *relationship = [relationships objectForKey:self.connectionMapping.relationshipName]; return relationship.isToMany; } - (BOOL)checkMatcher { if (!self.connectionMapping.matcher) { return YES; } else { return [self.connectionMapping.matcher isMatchForData:self.managedObject]; } } - (id)findConnected { if ([self checkMatcher]) { BOOL isToMany = [self isToMany]; id sourceValue = [self.managedObject valueForKey:self.connectionMapping.sourceKeyPath]; if (isToMany) { return [self findAllConnectedWithSourceValue:sourceValue]; } else { return [self findOneConnectedWithSourceValue:sourceValue]; } } else { return nil; } } - (void)connectRelationship { RKLogTrace(@"Connecting relationship '%@'", self.connectionMapping.relationshipName); [self.managedObjectContext performBlockAndWait:^{ id relatedObject = [self findConnected]; if (relatedObject) { [self.managedObject setValue:relatedObject forKeyPath:self.connectionMapping.relationshipName]; RKLogDebug(@"Connected relationship '%@' to object '%@'", self.connectionMapping.relationshipName, relatedObject); } else { RKEntityMapping *objectMapping = (RKEntityMapping *)self.connectionMapping.mapping; RKLogDebug(@"Failed to find instance of '%@' to connect relationship '%@'", [[objectMapping entity] name], self.connectionMapping.relationshipName); } }]; } - (void)main { if (self.isCancelled) return; @try { [self connectRelationship]; } @catch (NSException *exception) { RKLogCritical(@"Caught exception: %@", exception); } } @end