Skip to content

Commit 9103b9b

Browse files
committed
Merge branch 'release/0.20.0-pre5'
2 parents 3c84765 + baa9f62 commit 9103b9b

File tree

87 files changed

+1905
-540
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+1905
-540
lines changed

Code/CoreData/RKConnectionDescription.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
@param sourceToDestinationEntityAttributes A dictionary specifying how attributes on the source entity correspond to attributes on the destination entity.
8989
@return The receiver, initialized with the given relationship and attributes.
9090
*/
91-
- (id)initWithRelationship:(NSRelationshipDescription *)relationship attributes:(NSDictionary *)sourceToDestinationEntityAttributes;
91+
- (instancetype)initWithRelationship:(NSRelationshipDescription *)relationship attributes:(NSDictionary *)sourceToDestinationEntityAttributes;
9292

9393
/**
9494
The dictionary of attributes specifying how attributes on the source entity for the relationship correspond to attributes on the destination entity.
@@ -115,7 +115,7 @@
115115
@param keyPath The key path from which to read the value that is to be set for the relationship.
116116
@return The receiver, initialized with the given relationship and key path.
117117
*/
118-
- (id)initWithRelationship:(NSRelationshipDescription *)relationship keyPath:(NSString *)keyPath;
118+
- (instancetype)initWithRelationship:(NSRelationshipDescription *)relationship keyPath:(NSString *)keyPath;
119119

120120
/**
121121
The key path that is to be evaluated to obtain the value for the relationship.
@@ -144,9 +144,21 @@
144144
/// @name Setting the Predicate
145145
///----------------------------
146146

147+
/**
148+
Returns a Boolean value that determines if the connection includes subentities. If `NO`, then the connection will only be established to objects of exactly the entity specified by the relationship's entity. If `YES`, then the connection will be established to all objects of the relationship's entity and all subentities.
149+
150+
**Default**: `YES`
151+
*/
152+
@property (nonatomic, assign) BOOL includesSubentities;
153+
154+
/**
155+
An optional predicate for conditionally evaluating the connection based on the state of the source object.
156+
*/
157+
@property (nonatomic, strong) NSPredicate *sourcePredicate;
158+
147159
/**
148160
An optional predicate for filtering objects to be connected.
149161
*/
150-
@property (nonatomic, copy) NSPredicate *predicate;
162+
@property (nonatomic, copy) NSPredicate *destinationPredicate;
151163

152164
@end

Code/CoreData/RKConnectionDescription.m

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ @interface RKConnectionDescription ()
4444

4545
@implementation RKConnectionDescription
4646

47-
- (id)initWithRelationship:(NSRelationshipDescription *)relationship attributes:(NSDictionary *)attributes
47+
- (instancetype)initWithRelationship:(NSRelationshipDescription *)relationship attributes:(NSDictionary *)attributes
4848
{
4949
NSParameterAssert(relationship);
5050
NSParameterAssert(attributes);
@@ -58,11 +58,12 @@ - (id)initWithRelationship:(NSRelationshipDescription *)relationship attributes:
5858
if (self) {
5959
self.relationship = relationship;
6060
self.attributes = attributes;
61+
self.includesSubentities = YES;
6162
}
6263
return self;
6364
}
6465

65-
- (id)initWithRelationship:(NSRelationshipDescription *)relationship keyPath:(NSString *)keyPath
66+
- (instancetype)initWithRelationship:(NSRelationshipDescription *)relationship keyPath:(NSString *)keyPath
6667
{
6768
NSParameterAssert(relationship);
6869
NSParameterAssert(keyPath);
@@ -79,7 +80,7 @@ - (id)init
7980
if ([self class] == [RKConnectionDescription class]) {
8081
@throw [NSException exceptionWithName:NSInternalInconsistencyException
8182
reason:[NSString stringWithFormat:@"%@ Failed to call designated initializer. "
82-
"Invoke initWithRelationship:sourceKeyPath:destinationKeyPath:matcher: instead.",
83+
"Invoke initWithRelationship:attributes: instead.",
8384
NSStringFromClass([self class])]
8485
userInfo:nil];
8586
}

Code/CoreData/RKEntityByAttributeCache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
@return The receiver, initialized with the given entity, attribute, and managed object
4747
context.
4848
*/
49-
- (id)initWithEntity:(NSEntityDescription *)entity attributes:(NSArray *)attributeNames managedObjectContext:(NSManagedObjectContext *)context;
49+
- (instancetype)initWithEntity:(NSEntityDescription *)entity attributes:(NSArray *)attributeNames managedObjectContext:(NSManagedObjectContext *)context;
5050

5151
///-----------------------------
5252
/// @name Getting Cache Identity

Code/CoreData/RKEntityCache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
@param context The managed object context containing objects to be cached.
4444
@returns self, initialized with context.
4545
*/
46-
- (id)initWithManagedObjectContext:(NSManagedObjectContext *)context;
46+
- (instancetype)initWithManagedObjectContext:(NSManagedObjectContext *)context;
4747

4848
/**
4949
The managed object context with which the receiver is associated.

Code/CoreData/RKEntityCache.m

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ @interface RKEntityCache ()
2727

2828
@implementation RKEntityCache
2929

30-
3130
- (id)initWithManagedObjectContext:(NSManagedObjectContext *)context
3231
{
3332
NSAssert(context, @"Cannot initialize entity cache with a nil context");
@@ -45,7 +44,6 @@ - (id)init
4544
return [self initWithManagedObjectContext:nil];
4645
}
4746

48-
4947
- (void)cacheObjectsForEntity:(NSEntityDescription *)entity byAttributes:(NSArray *)attributeNames
5048
{
5149
NSParameterAssert(entity);

Code/CoreData/RKEntityMapping.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
@param entity An entity with which to initialize the receiver.
6969
@returns The receiver, initialized with the given entity.
7070
*/
71-
- (id)initWithEntity:(NSEntityDescription *)entity;
71+
- (instancetype)initWithEntity:(NSEntityDescription *)entity;
7272

7373
/**
7474
A convenience initializer that creates and returns an entity mapping for the entity with the given name in
@@ -83,7 +83,7 @@
8383
@param managedObjectStore A managed object store containing the managed object model in which an entity with the given name is defined.
8484
@return A new entity mapping for the entity with the given name in the managed object model of the given managed object store.
8585
*/
86-
+ (id)mappingForEntityForName:(NSString *)entityName inManagedObjectStore:(RKManagedObjectStore *)managedObjectStore;
86+
+ (instancetype)mappingForEntityForName:(NSString *)entityName inManagedObjectStore:(RKManagedObjectStore *)managedObjectStore;
8787

8888
///---------------------------
8989
/// @name Accessing the Entity

Code/CoreData/RKEntityMapping.m

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,27 @@
3636

3737
static NSArray *RKEntityIdentificationAttributesFromUserInfoOfEntity(NSEntityDescription *entity)
3838
{
39-
id userInfoValue = [[entity userInfo] valueForKey:RKEntityIdentificationAttributesUserInfoKey];
40-
if (userInfoValue) {
41-
NSArray *attributeNames = [userInfoValue isKindOfClass:[NSArray class]] ? userInfoValue : @[ userInfoValue ];
42-
NSMutableArray *attributes = [NSMutableArray arrayWithCapacity:[attributeNames count]];
43-
[attributeNames enumerateObjectsUsingBlock:^(NSString *attributeName, NSUInteger idx, BOOL *stop) {
44-
if (! [attributeName isKindOfClass:[NSString class]]) {
45-
[NSException raise:NSInvalidArgumentException format:@"Invalid value given in user info key '%@' of entity '%@': expected an `NSString` or `NSArray` of strings, instead got '%@' (%@)", RKEntityIdentificationAttributesUserInfoKey, [entity name], attributeName, [attributeName class]];
46-
}
47-
48-
NSAttributeDescription *attribute = [[entity attributesByName] valueForKey:attributeName];
49-
if (! attribute) {
50-
[NSException raise:NSInvalidArgumentException format:@"Invalid identifier attribute specified in user info key '%@' of entity '%@': no attribue was found with the name '%@'", RKEntityIdentificationAttributesUserInfoKey, [entity name], attributeName];
51-
}
52-
53-
[attributes addObject:attribute];
54-
}];
55-
return attributes;
56-
}
39+
do {
40+
id userInfoValue = [[entity userInfo] valueForKey:RKEntityIdentificationAttributesUserInfoKey];
41+
if (userInfoValue) {
42+
NSArray *attributeNames = [userInfoValue isKindOfClass:[NSArray class]] ? userInfoValue : @[ userInfoValue ];
43+
NSMutableArray *attributes = [NSMutableArray arrayWithCapacity:[attributeNames count]];
44+
[attributeNames enumerateObjectsUsingBlock:^(NSString *attributeName, NSUInteger idx, BOOL *stop) {
45+
if (! [attributeName isKindOfClass:[NSString class]]) {
46+
[NSException raise:NSInvalidArgumentException format:@"Invalid value given in user info key '%@' of entity '%@': expected an `NSString` or `NSArray` of strings, instead got '%@' (%@)", RKEntityIdentificationAttributesUserInfoKey, [entity name], attributeName, [attributeName class]];
47+
}
48+
49+
NSAttributeDescription *attribute = [[entity attributesByName] valueForKey:attributeName];
50+
if (! attribute) {
51+
[NSException raise:NSInvalidArgumentException format:@"Invalid identifier attribute specified in user info key '%@' of entity '%@': no attribue was found with the name '%@'", RKEntityIdentificationAttributesUserInfoKey, [entity name], attributeName];
52+
}
53+
54+
[attributes addObject:attribute];
55+
}];
56+
return attributes;
57+
}
58+
entity = [entity superentity];
59+
} while (entity);
5760

5861
return nil;
5962
}
@@ -137,20 +140,20 @@ @implementation RKEntityMapping
137140

138141
@synthesize identificationAttributes = _identificationAttributes;
139142

140-
+ (id)mappingForClass:(Class)objectClass
143+
+ (instancetype)mappingForClass:(Class)objectClass
141144
{
142145
@throw [NSException exceptionWithName:NSInternalInconsistencyException
143146
reason:[NSString stringWithFormat:@"You must provide a managedObjectStore. Invoke mappingForClass:inManagedObjectStore: instead."]
144147
userInfo:nil];
145148
}
146149

147-
+ (id)mappingForEntityForName:(NSString *)entityName inManagedObjectStore:(RKManagedObjectStore *)managedObjectStore
150+
+ (instancetype)mappingForEntityForName:(NSString *)entityName inManagedObjectStore:(RKManagedObjectStore *)managedObjectStore
148151
{
149152
NSEntityDescription *entity = [[managedObjectStore.managedObjectModel entitiesByName] objectForKey:entityName];
150153
return [[self alloc] initWithEntity:entity];
151154
}
152155

153-
- (id)initWithEntity:(NSEntityDescription *)entity
156+
- (instancetype)initWithEntity:(NSEntityDescription *)entity
154157
{
155158
NSAssert(entity, @"Cannot initialize an RKEntityMapping without an entity. Maybe you want RKObjectMapping instead?");
156159
Class objectClass = NSClassFromString([entity managedObjectClassName]);
@@ -164,7 +167,7 @@ - (id)initWithEntity:(NSEntityDescription *)entity
164167
return self;
165168
}
166169

167-
- (id)initWithClass:(Class)objectClass
170+
- (instancetype)initWithClass:(Class)objectClass
168171
{
169172
self = [super initWithClass:objectClass];
170173
if (self) {
@@ -275,7 +278,7 @@ - (Class)classForKeyPath:(NSString *)keyPath
275278
NSArray *components = [keyPath componentsSeparatedByString:@"."];
276279
Class propertyClass = self.objectClass;
277280
for (NSString *property in components) {
278-
propertyClass = [[RKPropertyInspector sharedInspector] classForPropertyNamed:property ofClass:propertyClass];
281+
propertyClass = [[RKPropertyInspector sharedInspector] classForPropertyNamed:property ofClass:propertyClass isPrimitive:nil];
279282
if (! propertyClass) propertyClass = [[RKPropertyInspector sharedInspector] classForPropertyNamed:property ofEntity:self.entity];
280283
if (! propertyClass) break;
281284
}

Code/CoreData/RKInMemoryManagedObjectCache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@
3535
@param managedObjectContext The managed object context with which to initialize the receiver.
3636
@return The receiver, initialized with the given managed object context.
3737
*/
38-
- (id)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext;
38+
- (instancetype)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext;
3939

4040
@end

Code/CoreData/RKManagedObjectImporter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
@warning As this initialization code path is typical for generating seed databases, the value of
5656
`resetsStoreBeforeImporting` is initialized to **YES**.
5757
*/
58-
- (id)initWithManagedObjectModel:(NSManagedObjectModel *)managedObjectModel storePath:(NSString *)storePath;
58+
- (instancetype)initWithManagedObjectModel:(NSManagedObjectModel *)managedObjectModel storePath:(NSString *)storePath;
5959

6060
/**
6161
Initializes the receiver with a given persistent store in which to persist imported managed objects.
@@ -69,7 +69,7 @@
6969
managed object model are determined from the given persistent store and a new managed object context with
7070
the private queue concurrency type is constructed.
7171
*/
72-
- (id)initWithPersistentStore:(NSPersistentStore *)persistentStore;
72+
- (instancetype)initWithPersistentStore:(NSPersistentStore *)persistentStore;
7373

7474
/**
7575
A Boolean value indicating whether existing managed objects in the persistent store should

Code/CoreData/RKManagedObjectImporter.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ - (NSUInteger)importObjectsFromFileAtPath:(NSString *)path withMapping:(RKMappin
213213
}
214214

215215
NSDictionary *mappingDictionary = @{ (keyPath ?: [NSNull null]) : mapping };
216-
RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithObject:parsedData mappingsDictionary:mappingDictionary];
216+
RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:parsedData mappingsDictionary:mappingDictionary];
217217
mapper.mappingOperationDataSource = self.mappingOperationDataSource;
218218
__block RKMappingResult *mappingResult;
219219
[self.managedObjectContext performBlockAndWait:^{

Code/CoreData/RKManagedObjectMappingOperationDataSource.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
@param managedObjectCache The managed object cache used by the receiver to find existing object instances by their identification attributes.
4343
@return The receiver, initialized with the given managed object context and managed objet cache.
4444
*/
45-
- (id)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext cache:(id<RKManagedObjectCaching>)managedObjectCache;
45+
- (instancetype)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext cache:(id<RKManagedObjectCaching>)managedObjectCache;
4646

4747
///-----------------------------------------------------
4848
/// @name Accessing the Managed Object Context and Cache

Code/CoreData/RKManagedObjectMappingOperationDataSource.m

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#import "RKRelationshipConnectionOperation.h"
3030
#import "RKMappingErrors.h"
3131
#import "RKValueTransformers.h"
32+
#import "RKRelationshipMapping.h"
33+
#import "RKObjectUtilities.h"
3234

3335
extern NSString * const RKObjectMappingNestingAttributeKeyName;
3436

@@ -128,19 +130,29 @@ @interface RKManagedObjectMappingOperationDataSource ()
128130

129131
@implementation RKManagedObjectMappingOperationDataSource
130132

131-
- (id)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext cache:(id<RKManagedObjectCaching>)managedObjectCache
133+
- (instancetype)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext cache:(id<RKManagedObjectCaching>)managedObjectCache
132134
{
133135
NSParameterAssert(managedObjectContext);
134136

135137
self = [self init];
136138
if (self) {
137139
self.managedObjectContext = managedObjectContext;
138140
self.managedObjectCache = managedObjectCache;
141+
142+
[[NSNotificationCenter defaultCenter] addObserver:self
143+
selector:@selector(updateCacheWithChangesFromContextWillSaveNotification:)
144+
name:NSManagedObjectContextWillSaveNotification
145+
object:managedObjectContext];
139146
}
140147

141148
return self;
142149
}
143150

151+
- (void)dealloc
152+
{
153+
[[NSNotificationCenter defaultCenter] removeObserver:self];
154+
}
155+
144156
- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRepresentation:(NSDictionary *)representation withMapping:(RKObjectMapping *)mapping
145157
{
146158
NSAssert(representation, @"Mappable data cannot be nil");
@@ -239,4 +251,61 @@ - (BOOL)commitChangesForMappingOperation:(RKMappingOperation *)mappingOperation
239251
return YES;
240252
}
241253

254+
// NOTE: In theory we should be able to use the userInfo dictionary, but the dictionary was coming in empty (12/18/2012)
255+
- (void)updateCacheWithChangesFromContextWillSaveNotification:(NSNotification *)notification
256+
{
257+
NSSet *objectsToAdd = [[self.managedObjectContext insertedObjects] setByAddingObjectsFromSet:[self.managedObjectContext updatedObjects]];
258+
259+
__block BOOL success;
260+
__block NSError *error = nil;
261+
[self.managedObjectContext performBlockAndWait:^{
262+
success = [self.managedObjectContext obtainPermanentIDsForObjects:[objectsToAdd allObjects] error:&error];
263+
}];
264+
265+
if (! success) {
266+
RKLogWarning(@"Failed obtaining permanent managed object ID's for %ld objects: the managed object cache was not updated and duplicate objects may be created.", (long) [objectsToAdd count]);
267+
RKLogError(@"Obtaining permanent managed object IDs failed with error: %@", error);
268+
return;
269+
}
270+
271+
// Update the cache
272+
if ([self.managedObjectCache respondsToSelector:@selector(didFetchObject:)]) {
273+
for (NSManagedObject *managedObject in objectsToAdd) {
274+
[self.managedObjectCache didFetchObject:managedObject];
275+
}
276+
}
277+
278+
if ([self.managedObjectCache respondsToSelector:@selector(didDeleteObject::)]) {
279+
for (NSManagedObject *managedObject in [self.managedObjectContext deletedObjects]) {
280+
[self.managedObjectCache didDeleteObject:managedObject];
281+
}
282+
}
283+
}
284+
285+
- (BOOL)mappingOperation:(RKMappingOperation *)mappingOperation deleteExistingValueOfRelationshipWithMapping:(RKRelationshipMapping *)relationshipMapping error:(NSError **)error
286+
{
287+
// Validate the assignment policy
288+
if (! relationshipMapping.assignmentPolicy == RKReplaceAssignmentPolicy) {
289+
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Unable to satisfy deletion request: Relationship mapping was expected to have an assignment policy of `RKReplaceAssignmentPolicy`, but did not." };
290+
NSError *localError = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorInvalidAssignmentPolicy userInfo:userInfo];
291+
if (error) *error = localError;
292+
return NO;
293+
}
294+
295+
// Delete any managed objects at the destination key path from the context
296+
id existingValue = [mappingOperation.destinationObject valueForKeyPath:relationshipMapping.destinationKeyPath];
297+
if ([existingValue isKindOfClass:[NSManagedObject class]]) {
298+
[self.managedObjectContext deleteObject:existingValue];
299+
} else {
300+
if (RKObjectIsCollection(existingValue)) {
301+
for (NSManagedObject *managedObject in existingValue) {
302+
if (! [managedObject isKindOfClass:[NSManagedObject class]]) continue;
303+
[self.managedObjectContext deleteObject:managedObject];
304+
}
305+
}
306+
}
307+
308+
return YES;
309+
}
310+
242311
@end

0 commit comments

Comments
 (0)