Skip to content

Commit 0e7bf23

Browse files
committed
Merge branch 'release/0.25.0'
2 parents 0b898aa + fecde9d commit 0e7bf23

File tree

71 files changed

+1114
-1100
lines changed

Some content is hidden

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

71 files changed

+1114
-1100
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ DerivedData
3333
# Bundler binstubs
3434
.bundle
3535
bin
36+
RestKit.xcscmblueprint

.gitmodules

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +0,0 @@
1-
[submodule "Vendor/AFNetworking"]
2-
path = Vendor/AFNetworking
3-
url = https://github.com/AFNetworking/AFNetworking.git
4-
[submodule "Vendor/TransitionKit"]
5-
path = Vendor/TransitionKit
6-
url = https://github.com/blakewatters/TransitionKit.git
7-
[submodule "Vendor/RKValueTransformers"]
8-
path = Vendor/RKValueTransformers
9-
url = https://github.com/RestKit/RKValueTransformers.git
10-
[submodule "Vendor/ISO8601DateFormatterValueTransformer"]
11-
path = Vendor/ISO8601DateFormatterValueTransformer
12-
url = https://github.com/blakewatters/ISO8601DateFormatterValueTransformer.git
13-
[submodule "Vendor/SOCKit"]
14-
path = Vendor/SOCKit
15-
url = https://github.com/NimbusKit/sockit.git

.ruby-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.2.1
1+
2.2.2

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
language: objective-c
2-
rvm: 2.2.1
2+
rvm: 2.2.2
33
install:
44
- bundle install
55
- bundle exec pod install

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## Issues
22

3-
GitHub Issues is for reporting bugs in RestKit and discussing changes to RestKit itself. Please check the [documentation](http://cocoadocs.org/docsets/RestKit/), [wiki](https://github.com/RestKit/RestKit/wiki), and [existing issues](https://github.com/RestKit/RestKit/issues?state=closed) before opening a new issue.
3+
GitHub Issues is for reporting bugs in RestKit and discussing changes to RestKit itself. Please check the [documentation](http://cocoadocs.org/docsets/RestKit/), [wiki](https://github.com/RestKit/RestKit/wiki), and [existing issues](https://github.com/RestKit/RestKit/issues?q=is:issue) before opening a new issue.
44

55
Additionaly, please do not post general usage questions to Issues, but instead take them to [Stack Overflow](http://stackoverflow.com/questions/tagged/restkit).
66

Code/CoreData/RKEntityMapping.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,13 @@
114114
*/
115115
@property (nonatomic, copy) NSPredicate *identificationPredicate;
116116

117+
/**
118+
An optional block which returns a predicate used to filter identified objects during mapping.
119+
120+
@return The identification predicate block.
121+
*/
122+
@property (nonatomic, copy) NSPredicate *(^identificationPredicateBlock)(NSDictionary *representation, NSManagedObjectContext *managedObjectContext);
123+
117124
/**
118125
An optional attribute of the receiver's entity that can be used to detect modification of a given instance. This is used to improve the performance of mapping operations by skipping the property mappings for a given object if it is found to be not modified.
119126

Code/CoreData/RKEntityMapping.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ - (id)copyWithZone:(NSZone *)zone
190190
copy.entity = self.entity;
191191
copy.identificationAttributes = self.identificationAttributes;
192192
copy.identificationPredicate = self.identificationPredicate;
193+
copy.identificationPredicateBlock = self.identificationPredicateBlock;
193194
copy.deletionPredicate = self.deletionPredicate;
194195
copy.modificationAttribute = self.modificationAttribute;
195196
copy.mutableConnections = [NSMutableArray array];

Code/CoreData/RKManagedObjectMappingOperationDataSource.m

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,11 @@ - (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRep
253253
if (existingObjectsOfRelationship && !RKObjectIsCollection(existingObjectsOfRelationship)) existingObjectsOfRelationship = @[ existingObjectsOfRelationship ];
254254
NSSet *setWithNull = [NSSet setWithObject:[NSNull null]];
255255
for (NSManagedObject *existingObject in existingObjectsOfRelationship) {
256-
if (! identificationAttributes && ![existingObject isDeleted]) {
256+
if(existingObject.isDeleted) {
257+
continue;
258+
}
259+
260+
if (!identificationAttributes) {
257261
managedObject = existingObject;
258262
[existingObjectsOfRelationship removeObject:managedObject];
259263
break;
@@ -273,6 +277,10 @@ - (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRep
273277
attributeValues:entityIdentifierAttributes
274278
inManagedObjectContext:self.managedObjectContext];
275279
if (entityMapping.identificationPredicate) objects = [objects filteredSetUsingPredicate:entityMapping.identificationPredicate];
280+
if (entityMapping.identificationPredicateBlock) {
281+
NSPredicate *predicate = entityMapping.identificationPredicateBlock(representation, self.managedObjectContext);
282+
if (predicate) objects = [objects filteredSetUsingPredicate:predicate];
283+
}
276284
if ([objects count] > 0) {
277285
managedObject = [objects anyObject];
278286
if ([objects count] > 1) RKLogWarning(@"Managed object cache returned %ld objects for the identifier configured for the '%@' entity, expected 1.", (long) [objects count], [entity name]);

Code/CoreData/RKManagedObjectStore.m

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,31 @@ - (void)handleManagedObjectContextDidSaveNotification:(NSNotification *)notifica
103103
NSAssert([notification object] == self.observedContext, @"Received Managed Object Context Did Save Notification for Unexpected Context: %@", [notification object]);
104104
if (! [self.objectIDsFromChildDidSaveNotification isEqual:RKSetOfManagedObjectIDsFromManagedObjectContextDidSaveNotification(notification)]) {
105105
[self.mergeContext performBlock:^{
106+
107+
/*
108+
Fault updated objects before merging changes into mainQueueManagedObjectContext.
109+
110+
This enables NSFetchedResultsController to update and re-sort its fetch results and to call its delegate methods
111+
in response Managed Object updates merged from another context.
112+
See:
113+
http://stackoverflow.com/a/3927811/489376
114+
http://stackoverflow.com/a/16296365/489376
115+
for issue details.
116+
*/
117+
for (NSManagedObject *object in [[notification userInfo] objectForKey:NSUpdatedObjectsKey]) {
118+
NSManagedObjectID *objectID = [object objectID];
119+
if (objectID && ![objectID isTemporaryID]) {
120+
NSError *error = nil;
121+
NSManagedObject * updatedObject = [self.mergeContext existingObjectWithID:objectID error:&error];
122+
if (error) {
123+
RKLogDebug(@"Failed to get existing object for objectID (%@). Failed with error: %@", objectID, error);
124+
}
125+
else {
126+
[updatedObject willAccessValueForKey:nil];
127+
}
128+
}
129+
}
130+
106131
[self.mergeContext mergeChangesFromContextDidSaveNotification:notification];
107132
}];
108133
} else {

Code/CoreData/RKRelationshipConnectionOperation.m

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,14 @@ - (id)findConnectedValueForConnection:(RKConnectionDescription *)connection shou
148148
{
149149
*shouldConnectRelationship = YES;
150150
id connectionResult = nil;
151-
if (connection.sourcePredicate && ![connection.sourcePredicate evaluateWithObject:self.managedObject]) return nil;
151+
if (connection.sourcePredicate) {
152+
__block BOOL evaluationResult;
153+
[self.managedObject.managedObjectContext performBlockAndWait:^{
154+
evaluationResult = [connection.sourcePredicate evaluateWithObject:self.managedObject];
155+
}];
156+
157+
if (!evaluationResult) return nil;
158+
}
152159

153160
if ([connection isForeignKeyConnection]) {
154161
NSDictionary *attributeValues = RKConnectionAttributeValuesWithObject(connection, self.managedObject);
@@ -157,11 +164,15 @@ - (id)findConnectedValueForConnection:(RKConnectionDescription *)connection shou
157164
*shouldConnectRelationship = NO;
158165
return nil;
159166
}
160-
NSSet *managedObjects = [self.managedObjectCache managedObjectsWithEntity:[connection.relationship destinationEntity]
161-
attributeValues:attributeValues
162-
inManagedObjectContext:self.managedObjectContext];
163-
if (connection.destinationPredicate) managedObjects = [managedObjects filteredSetUsingPredicate:connection.destinationPredicate];
164-
if (!connection.includesSubentities) managedObjects = [managedObjects filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"entity == %@", [connection.relationship destinationEntity]]];
167+
__block NSSet *managedObjects = [self.managedObjectCache managedObjectsWithEntity:[connection.relationship destinationEntity]
168+
attributeValues:attributeValues
169+
inManagedObjectContext:self.managedObjectContext];
170+
171+
[self.managedObjectContext performBlockAndWait:^{
172+
if (connection.destinationPredicate) managedObjects = [managedObjects filteredSetUsingPredicate:connection.destinationPredicate];
173+
if (!connection.includesSubentities) managedObjects = [managedObjects filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"entity == %@", [connection.relationship destinationEntity]]];
174+
}];
175+
165176
if ([connection.relationship isToMany]) {
166177
connectionResult = managedObjects;
167178
} else {

Code/Network/RKHTTPRequestOperation.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
// limitations under the License.
1919
//
2020

21-
#import "AFHTTPClient.h"
22-
#import "AFHTTPRequestOperation.h"
21+
#import <AFNetworking/AFHTTPClient.h>
22+
#import <AFNetworking/AFHTTPRequestOperation.h>
2323

2424
// Expose the default headers from AFNetworking's AFHTTPClient
2525
@interface AFHTTPClient ()

Code/Network/RKManagedObjectRequestOperation.m

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -335,22 +335,22 @@ - (RKMappingResult *)refetchedMappingResult
335335
return URL;
336336
}
337337

338-
static NSSet *RKGatherManagedObjectsFromObjectWithRelationshipMapping(id object, RKRelationshipMapping *relationshipMapping)
338+
static void RKGatherManagedObjectsFromObjectWithRelationshipMapping(id object, RKRelationshipMapping *relationshipMapping, NSMutableSet *managedObjects)
339339
{
340-
NSMutableSet *managedObjects = [NSMutableSet set];
341340
NSSet *relationshipValue = RKFlattenCollectionToSet([object valueForKeyPath:relationshipMapping.destinationKeyPath]);
342341
for (id relatedObject in relationshipValue) {
342+
if ([managedObjects containsObject:relatedObject]) continue;
343343
if ([relatedObject isKindOfClass:[NSManagedObject class]]) [managedObjects addObject:relatedObject];
344-
344+
345345
if ([relationshipMapping.mapping isKindOfClass:[RKObjectMapping class]]) {
346346
for (RKRelationshipMapping *childRelationshipMapping in [(RKObjectMapping *)relationshipMapping.mapping relationshipMappings]) {
347-
[managedObjects unionSet:RKGatherManagedObjectsFromObjectWithRelationshipMapping(relatedObject, childRelationshipMapping)];
347+
RKGatherManagedObjectsFromObjectWithRelationshipMapping(relatedObject, childRelationshipMapping, managedObjects);
348348
}
349349
} else if ([relationshipMapping.mapping isKindOfClass:[RKDynamicMapping class]]) {
350350
for (RKObjectMapping *objectMapping in [(RKDynamicMapping *)relationshipMapping.mapping objectMappings]) {
351351
@try {
352352
for (RKRelationshipMapping *childRelationshipMapping in objectMapping.relationshipMappings) {
353-
[managedObjects unionSet:RKGatherManagedObjectsFromObjectWithRelationshipMapping(relatedObject, childRelationshipMapping)];
353+
RKGatherManagedObjectsFromObjectWithRelationshipMapping(relatedObject, childRelationshipMapping, managedObjects);
354354
}
355355
}
356356
@catch (NSException *exception) {
@@ -359,7 +359,6 @@ - (RKMappingResult *)refetchedMappingResult
359359
}
360360
}
361361
}
362-
return managedObjects;
363362
}
364363

365364
static NSSet *RKManagedObjectsFromObjectWithMappingInfo(id object, RKMappingInfo *mappingInfo)
@@ -373,15 +372,32 @@ - (RKMappingResult *)refetchedMappingResult
373372
if ([[mappingInfo propertyMappings] count] == 0) {
374373
// This object was matched, but no changes were made. Gather all related objects
375374
for (RKRelationshipMapping *relationshipMapping in [mappingInfo.objectMapping relationshipMappings]) {
376-
[managedObjects unionSet:RKGatherManagedObjectsFromObjectWithRelationshipMapping(object, relationshipMapping)];
375+
RKGatherManagedObjectsFromObjectWithRelationshipMapping(object, relationshipMapping, managedObjects);
377376
}
378-
} else {
377+
} else {
379378
for (NSString *destinationKeyPath in mappingInfo.relationshipMappingInfo) {
380-
id relationshipValue = [object valueForKeyPath:destinationKeyPath];
379+
id relationshipValue = nil;
380+
// Objects in collection may have different types, so destination keypath may be not applicable to each of them
381+
if([object conformsToProtocol:@protocol(NSFastEnumeration)]) {
382+
NSMutableSet* results = [NSMutableSet set];
383+
for (id item in object) {
384+
@try {
385+
id value = [item valueForKeyPath:destinationKeyPath];
386+
[results addObject:value];
387+
} @catch(NSException*) {
388+
continue;
389+
}
390+
}
391+
392+
relationshipValue = results;
393+
} else {
394+
relationshipValue = [object valueForKeyPath:destinationKeyPath];
395+
}
396+
381397
NSArray *mappingInfos = (mappingInfo.relationshipMappingInfo)[destinationKeyPath];
382398
for (RKMappingInfo *relationshipMappingInfo in mappingInfos) {
383399
NSUInteger index = [mappingInfos indexOfObject:relationshipMappingInfo];
384-
id mappedObjectAtIndex = ([relationshipValue respondsToSelector:@selector(objectAtIndex:)]) ? [NSSet setWithObject:relationshipValue[index]] : relationshipValue;
400+
id mappedObjectAtIndex = ([relationshipValue respondsToSelector:@selector(objectAtIndex:)]) ? relationshipValue[index] : relationshipValue;
385401
[managedObjects unionSet:RKFlattenCollectionToSet(RKManagedObjectsFromObjectWithMappingInfo(mappedObjectAtIndex, relationshipMappingInfo))];
386402
}
387403
}
@@ -400,7 +416,7 @@ - (RKMappingResult *)refetchedMappingResult
400416
id objectsAtRoot = mappingResultDictionary[rootKey];
401417
for (RKMappingInfo *mappingInfo in mappingInfoArray) {
402418
NSUInteger index = [mappingInfoArray indexOfObject:mappingInfo];
403-
id mappedObjectAtIndex = ([objectsAtRoot respondsToSelector:@selector(objectAtIndex:)]) ? [NSSet setWithObject:objectsAtRoot[index]] : objectsAtRoot;
419+
id mappedObjectAtIndex = ([objectsAtRoot respondsToSelector:@selector(objectAtIndex:)]) ? objectsAtRoot[index] : objectsAtRoot;
404420

405421
NSSet *managedObjects = RKManagedObjectsFromObjectWithMappingInfo(mappedObjectAtIndex, mappingInfo);
406422
if (managedObjects) {
@@ -733,7 +749,10 @@ - (BOOL)deleteLocalObjectsMissingFromMappingResult:(RKMappingResult *)mappingRes
733749
if (! [fetchRequests count]) return YES;
734750

735751
// Proceed with cleanup
736-
NSSet *managedObjectsInMappingResult = RKManagedObjectsFromMappingResultWithMappingInfo(mappingResult, self.mappingInfo) ?: [NSSet set];
752+
__block NSSet *managedObjectsInMappingResult;
753+
[self.privateContext performBlockAndWait:^{
754+
managedObjectsInMappingResult = RKManagedObjectsFromMappingResultWithMappingInfo(mappingResult, self.mappingInfo) ?: [NSSet set];
755+
}];
737756
NSSet *localObjects = [self localObjectsFromFetchRequests:fetchRequests matchingRequestURL:error];
738757
if (! localObjects) {
739758
RKLogError(@"Failed when attempting to fetch local candidate objects for orphan cleanup: %@", error ? *error : nil);

Code/Network/RKObjectManager.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@
2121
#import "RKRouter.h"
2222
#import "RKPaginator.h"
2323
#import "RKMacros.h"
24-
#import "AFNetworking.h"
24+
25+
#import <AFNetworking/AFNetworking.h>
2526

2627
#ifdef _COREDATADEFINES_H
27-
#if __has_include("RKCoreData.h")
28-
#define RKCoreDataIncluded
29-
#endif
28+
# if __has_include("RKCoreData.h")
29+
# define RKCoreDataIncluded
30+
# endif
3031
#endif
3132

3233
@protocol RKSerialization;

Code/Network/RKObjectManager.m

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,16 @@
3838
#import "RKRouteSet.h"
3939

4040
#ifdef _COREDATADEFINES_H
41-
#if __has_include("RKCoreData.h")
42-
#define RKCoreDataIncluded
43-
#import "RKManagedObjectStore.h"
44-
#import "RKManagedObjectRequestOperation.h"
45-
#endif
41+
# if __has_include("RKCoreData.h")
42+
# define RKCoreDataIncluded
43+
# import "RKManagedObjectStore.h"
44+
# import "RKManagedObjectRequestOperation.h"
45+
# endif
4646
#endif
4747

4848
#if !__has_feature(objc_arc)
49-
#error RestKit must be built with ARC.
50-
// You can turn on ARC for only RestKit files by adding "-fobjc-arc" to the build phase for each of its files.
49+
#error RestKit must be built with ARC. \
50+
You can turn on ARC for only RestKit files by adding "-fobjc-arc" to the build phase for each of its files.
5151
#endif
5252

5353
//////////////////////////////////

Code/Network/RKResponseMapperOperation.m

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,10 +311,12 @@ - (void)willFinish
311311
{
312312
if (self.isCancelled && !self.error) self.error = [NSError errorWithDomain:RKErrorDomain code:RKOperationCancelledError userInfo:@{ NSLocalizedDescriptionKey: @"The operation was cancelled." }];
313313

314-
if (self.didFinishMappingBlock) {
315-
if (self.error) self.didFinishMappingBlock(nil, self.error);
316-
else self.didFinishMappingBlock(self.mappingResult, nil);
317-
[self setDidFinishMappingBlock:nil];
314+
@synchronized(self) {
315+
if (self.didFinishMappingBlock) {
316+
if (self.error) self.didFinishMappingBlock(nil, self.error);
317+
else self.didFinishMappingBlock(self.mappingResult, nil);
318+
[self setDidFinishMappingBlock:nil];
319+
}
318320
}
319321
}
320322

Code/ObjectMapping.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818
// limitations under the License.
1919
//
2020

21+
#import <RKValueTransformers/RKValueTransformers.h>
22+
2123
#import "RKObjectMapping.h"
2224
#import "RKAttributeMapping.h"
2325
#import "RKRelationshipMapping.h"
24-
#import "RKValueTransformers.h"
2526
#import "RKMappingResult.h"
2627
#import "RKMapperOperation.h"
2728
#import "RKDynamicMapping.h"

Code/ObjectMapping/RKHTTPUtilities.m

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,13 @@ RKRequestMethod RKRequestMethodFromString(NSString *methodName)
344344
int parsed = 0, cs = 1;
345345
NSDate *date = NULL;
346346

347+
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && (__IPHONE_OS_VERSION_MAX_ALLOWED < 70000)) || \
348+
(defined(MAC_OS_X_VERSION_MAX_ALLOWED) && (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9))
347349
CFGregorianDate gdate;
348350
memset(&gdate, 0, sizeof(CFGregorianDate));
351+
#else
352+
NSDateComponents *gdate = [[NSDateComponents alloc] init];
353+
#endif
349354

350355
{
351356
int _slen, _trans;
@@ -397,11 +402,29 @@ RKRequestMethod RKRequestMethodFromString(NSString *methodName)
397402
_out: {}
398403
}
399404

400-
static CFTimeZoneRef gmtTimeZone;
401405
static dispatch_once_t onceToken;
402-
dispatch_once(&onceToken, ^{ gmtTimeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0.0); });
403406

404-
if(parsed == 1) { date = [NSDate dateWithTimeIntervalSinceReferenceDate:CFGregorianDateGetAbsoluteTime(gdate, gmtTimeZone)]; }
407+
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && (__IPHONE_OS_VERSION_MAX_ALLOWED < 70000)) || \
408+
(defined(MAC_OS_X_VERSION_MAX_ALLOWED) && (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9))
409+
static CFTimeZoneRef gmtTimeZone;
410+
dispatch_once(&onceToken, ^{
411+
gmtTimeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0.0);
412+
});
413+
414+
if (parsed == 1) {
415+
date = [NSDate dateWithTimeIntervalSinceReferenceDate:CFGregorianDateGetAbsoluteTime(gdate, gmtTimeZone)];
416+
}
417+
#else
418+
static NSCalendar *gregorian;
419+
dispatch_once(&onceToken, ^{
420+
gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
421+
gregorian.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
422+
});
423+
424+
if (parsed == 1) {
425+
date = [gregorian dateFromComponents:gdate];
426+
}
427+
#endif
405428

406429
return(date);
407430
}

0 commit comments

Comments
 (0)