Convert RKConnectionMapping into a subclass of RKPropertyMapping. Add delegate callback for tracking the connection of relationships.

This commit is contained in:
Blake Watters
2012-09-29 17:49:13 -04:00
parent 0539aeb45e
commit 4c401de6bf
6 changed files with 82 additions and 68 deletions

View File

@@ -149,10 +149,19 @@ extern NSString * const RKObjectMappingNestingAttributeKeyName;
RKRelationshipConnectionOperation *operation = [[RKRelationshipConnectionOperation alloc] initWithManagedObject:mappingOperation.destinationObject
connectionMapping:connectionMapping
managedObjectCache:self.managedObjectCache];
// TODO: This should really be done using dependencies...
if (self.operationQueue) {
[self.operationQueue addOperation:operation];
[operation setCompletionBlock:^{
if ([mappingOperation.delegate respondsToSelector:@selector(mappingOperation:didConnectRelationship:usingMapping:)]) {
[mappingOperation.delegate mappingOperation:mappingOperation didConnectRelationship:connectionMapping.relationship usingMapping:connectionMapping];
}
}];
} else {
[operation start];
if ([mappingOperation.delegate respondsToSelector:@selector(mappingOperation:didConnectRelationship:usingMapping:)]) {
[mappingOperation.delegate mappingOperation:mappingOperation didConnectRelationship:connectionMapping.relationship usingMapping:connectionMapping];
}
}
}
}

View File

@@ -5,6 +5,18 @@
// Created by Blake Watters on 7/12/12.
// Copyright (c) 2012 RestKit. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import <Foundation/Foundation.h>
@@ -12,36 +24,17 @@
@protocol RKManagedObjectCaching;
/**
The RKRelationshipConnectionOperation class is a subclass of NSOperation that manages the connection
of NSManagedObject relationships as described by an RKConnectionMapping object. When executed, the
operation will find related objects by searching the associated managed object cache for a matching object
whose destination attribute value matches that of the associated managed object's source attribute.
The `RKRelationshipConnectionOperation` class is a subclass of `NSOperation` that manages the connection of `NSManagedObject` relationships as described by an `RKConnectionMapping` object. When executed, the operation will find related objects by searching the associated managed object cache for a matching object whose destination attribute value matches that of the associated managed object's source attribute.
For example, given a managed object for the `Employee` entity with a one-to-one relationship to a `Company` named `company`
(with an inverse relationship one-to-many relationship named `employees`) and a connection mapping specifying that
the relationship can be connected by finding the `Company` managed object whose `companyID` attribute matches the
`companyID` of the `Employee`, the operation would find the Company that employs the Employee by primary key and set
the Core Data relationship to reflect the relationship appropriately.
For example, given a managed object for the `Employee` entity with a one-to-one relationship to a `Company` named `company` (with an inverse relationship one-to-many relationship named `employees`) and a connection mapping specifying that the relationship can be connected by finding the `Company` managed object whose `companyID` attribute matches the `companyID` of the `Employee`, the operation would find the Company that employs the Employee by primary key and set the Core Data relationship to reflect the relationship appropriately.
@see RKConnectionMapping
@see `RKConnectionMapping`
*/
@interface RKRelationshipConnectionOperation : NSOperation
/**
The managed object the receiver will attempt to connect a relationship for.
*/
@property (nonatomic, strong, readonly) NSManagedObject *managedObject;
/**
The connection mapping describing the relationship connection the receiver will attempt to connect.
*/
@property (nonatomic, strong, readonly) RKConnectionMapping *connectionMapping;
/**
The managed object cache the receiver will use to fetch a related object satisfying the connection
mapping.
*/
@property (nonatomic, strong, readonly) id<RKManagedObjectCaching> managedObjectCache;
///-------------------------------------------------------
/// @name Initializing a Relationship Connection Operation
///-------------------------------------------------------
/**
Initializes the receiver with a given managed object, connection mapping, and managed object cache.
@@ -55,4 +48,23 @@
connectionMapping:(RKConnectionMapping *)connectionMapping
managedObjectCache:(id<RKManagedObjectCaching>)managedObjectCache;
///--------------------------------------------
/// @name Accessing Details About the Operation
///--------------------------------------------
/**
The managed object the receiver will attempt to connect a relationship for.
*/
@property (nonatomic, strong, readonly) NSManagedObject *managedObject;
/**
The connection mapping describing the relationship connection the receiver will attempt to connect.
*/
@property (nonatomic, strong, readonly) RKConnectionMapping *connectionMapping;
/**
The managed object cache the receiver will use to fetch a related object satisfying the connection mapping.
*/
@property (nonatomic, strong, readonly) id<RKManagedObjectCaching> managedObjectCache;
@end

View File

@@ -5,6 +5,18 @@
// Created by Blake Watters on 7/12/12.
// Copyright (c) 2012 RestKit. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import <CoreData/CoreData.h>
#import "RKRelationshipConnectionOperation.h"
@@ -12,6 +24,7 @@
#import "RKLog.h"
#import "RKManagedObjectCaching.h"
#import "RKDynamicMappingMatcher.h"
#import "RKErrors.h"
// Set Logging Component
#undef RKLogComponent
@@ -21,6 +34,7 @@
@property (nonatomic, strong, readwrite) NSManagedObject *managedObject;
@property (nonatomic, strong, readwrite) RKConnectionMapping *connectionMapping;
@property (nonatomic, strong, readwrite) id<RKManagedObjectCaching> managedObjectCache;
@property (nonatomic, strong, readwrite) NSError *error;
// Helpers
@property (weak, nonatomic, readonly) NSManagedObjectContext *managedObjectContext;
@@ -169,24 +183,15 @@
RKLogTrace(@"Connecting relationship '%@' with mapping: %@", relationshipName, self.connectionMapping);
[self.managedObjectContext performBlockAndWait:^{
id relatedObject = [self findConnected];
if (relatedObject) {
[self.managedObject setValue:relatedObject forKeyPath:relationshipName];
RKLogDebug(@"Connected relationship '%@' to object '%@'", relationshipName, relatedObject);
} else {
RKLogDebug(@"Failed to find instance of '%@' to connect relationship '%@'", [[self.connectionMapping.relationship destinationEntity] name], relationshipName);
}
[self.managedObject setValue:relatedObject forKeyPath:relationshipName];
RKLogDebug(@"Connected relationship '%@' to object '%@'", relationshipName, relatedObject);
}];
}
- (void)main
{
if (self.isCancelled) return;
@try {
[self connectRelationship];
}
@catch (NSException *exception) {
RKLogCritical(@"Caught exception: %@", exception);
}
[self connectRelationship];
}
@end

View File

@@ -21,12 +21,11 @@
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "RKMapping.h"
#import "RKPropertyMapping.h"
@class RKConnectionMapping, RKDynamicMappingMatcher;
@protocol RKManagedObjectCaching;
typedef id (^RKObjectConnectionBlock)(RKConnectionMapping *mapping, id source);
// Defines the rules for connecting relationsips
/**
Instructs RestKit to connect a relationship of the object being mapped to the
@@ -93,11 +92,10 @@ typedef id (^RKObjectConnectionBlock)(RKConnectionMapping *mapping, id source);
@see connectRelationship:withObjectForPrimaryKeyAttribute:
*/
@interface RKConnectionMapping : NSObject
@interface RKConnectionMapping : RKPropertyMapping
@property (nonatomic, strong, readonly) NSRelationshipDescription *relationship;
@property (nonatomic, strong, readonly) NSString *sourceKeyPath;
@property (nonatomic, strong, readonly) NSString *destinationKeyPath;
@property (nonatomic, strong, readonly) RKDynamicMappingMatcher *matcher; // Can be nil
// Returns YES if the receiver describes a connection between entities that is established

View File

@@ -41,31 +41,6 @@
@implementation RKConnectionMapping
//+ (RKConnectionMapping *)connectionMappingForRelationship:(NSString *)relationshipName fromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath withMapping:(RKMapping *)objectOrDynamicMapping
//{
// RKConnectionMapping *mapping = [[self alloc] initWithRelationshipName:relationshipName sourceKeyPath:sourceKeyPath destinationKeyPath:destinationKeyPath mapping:objectOrDynamicMapping matcher:nil];
// return mapping;
//}
//
//+ (RKConnectionMapping*)connectionMappingForRelationship:(NSString *)relationshipName fromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath withMapping:(RKMapping *)objectOrDynamicMapping matcher:(RKDynamicMappingMatcher *)matcher
//{
// RKConnectionMapping *mapping = [[self alloc] initWithRelationshipName:relationshipName sourceKeyPath:sourceKeyPath destinationKeyPath:destinationKeyPath mapping:objectOrDynamicMapping matcher:matcher];
// return mapping;
//}
//
//- (id)initWithRelationshipName:(NSString *)relationshipName sourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath mapping:(RKMapping *)objectOrDynamicMapping matcher:(RKDynamicMappingMatcher *)matcher
//{
// self = [super init];
// if (self) {
// self.relationshipName = relationshipName;
// self.sourceKeyPath = sourceKeyPath;
// self.destinationKeyPath = destinationKeyPath;
// self.mapping = objectOrDynamicMapping;
// self.matcher = matcher;
// }
// return self;
//}
- (Class)connectionMappingClassForRelationship:(NSRelationshipDescription *)relationship sourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath
{
NSEntityDescription *sourceEntity = relationship.entity;

View File

@@ -21,7 +21,7 @@
#import "RKObjectMapping.h"
#import "RKAttributeMapping.h"
@class RKMappingOperation, RKDynamicMapping;
@class RKMappingOperation, RKDynamicMapping, RKConnectionMapping;
@protocol RKMappingOperationDataSource;
/**
@@ -88,6 +88,21 @@
*/
- (void)mappingOperation:(RKMappingOperation *)operation didSelectObjectMapping:(RKObjectMapping *)objectMapping forDynamicMapping:(RKDynamicMapping *)dynamicMapping;
#ifdef _COREDATADEFINES_H
/**
Tells the delegate that the mapping operation has connected a relationship.
Only sent when mapping an `RKEntityMapping` object that contains connection mappings.
@param operation The mapping operation.
@param relationship The relationship that was connected.
@param connectionMapping The mappings that was used to connect the relationship.
*/
- (void)mappingOperation:(RKMappingOperation *)operation didConnectRelationship:(NSRelationshipDescription *)relationship usingMapping:(RKConnectionMapping *)connectionMapping;
#endif
@end
/**