Skip to content

Commit b1aa942

Browse files
committed
Merge branch 'release/0.20.2'
2 parents 7df317b + e0b7d4a commit b1aa942

Some content is hidden

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

45 files changed

+221
-7805
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,6 @@ test-reports/
2525

2626
# CocoaPods
2727
Pods
28+
RestKit.xcodeproj/xcshareddata/
29+
RestKit.xcworkspace/xcshareddata/xcschemes/
30+
DerivedData

Code/Network/RKManagedObjectRequestOperation.m

+25-2
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ - (BOOL)canSkipMapping
526526
BOOL (^shouldSkipMapping)(void) = ^{
527527
// Is the request cacheable
528528
if (!self.cachedResponse) return NO;
529+
if (!self.managedObjectCache) return NO;
529530
NSURLRequest *request = self.HTTPRequestOperation.request;
530531
if (! [[request HTTPMethod] isEqualToString:@"GET"] && ! [[request HTTPMethod] isEqualToString:@"HEAD"]) return NO;
531532
NSHTTPURLResponse *response = (NSHTTPURLResponse *)self.HTTPRequestOperation.response;
@@ -666,7 +667,7 @@ - (BOOL)deleteTargetObjectIfAppropriate:(NSError **)error
666667
return _blockSuccess;
667668
}
668669

669-
- (NSSet *)localObjectsFromFetchRequestsMatchingRequestURL:(NSError **)error
670+
- (NSSet *)localObjectsFromFetchRequests:(NSArray *)fetchRequests matchingRequestURL:(NSError **)error
670671
{
671672
NSMutableSet *localObjects = [NSMutableSet set];
672673
__block NSError *_blockError;
@@ -699,6 +700,23 @@ - (NSSet *)localObjectsFromFetchRequestsMatchingRequestURL:(NSError **)error
699700
return localObjects;
700701
}
701702

703+
- (NSArray *)fetchRequestsMatchingResponseURL
704+
{
705+
// Pass the fetch request blocks a relative `NSURL` object if possible
706+
NSMutableArray *fetchRequests = [NSMutableArray array];
707+
NSURL *URL = RKRelativeURLFromURLAndResponseDescriptors(self.HTTPRequestOperation.response.URL, self.responseDescriptors);
708+
for (RKFetchRequestBlock fetchRequestBlock in [self.fetchRequestBlocks reverseObjectEnumerator]) {
709+
NSFetchRequest *fetchRequest = fetchRequestBlock(URL);
710+
if (fetchRequest) {
711+
// Workaround for iOS 5 -- The log statement crashes if the entity is not assigned before logging
712+
[fetchRequest setEntity:[[[[self.privateContext persistentStoreCoordinator] managedObjectModel] entitiesByName] objectForKey:[fetchRequest entityName]]];
713+
RKLogDebug(@"Found fetch request matching URL '%@': %@", URL, fetchRequest);
714+
[fetchRequests addObject:fetchRequest];
715+
}
716+
}
717+
return fetchRequests;
718+
}
719+
702720
- (BOOL)deleteLocalObjectsMissingFromMappingResult:(RKMappingResult *)mappingResult error:(NSError **)error
703721
{
704722
if (! self.deletesOrphanedObjects) {
@@ -716,8 +734,13 @@ - (BOOL)deleteLocalObjectsMissingFromMappingResult:(RKMappingResult *)mappingRes
716734
return YES;
717735
}
718736

737+
// Determine if there are any fetch request blocks to use for orphaned object cleanup
738+
NSArray *fetchRequests = [self fetchRequestsMatchingResponseURL];
739+
if (! [fetchRequests count]) return YES;
740+
741+
// Proceed with cleanup
719742
NSSet *managedObjectsInMappingResult = RKManagedObjectsFromMappingResultWithMappingInfo(mappingResult, self.mappingInfo) ?: [NSSet set];
720-
NSSet *localObjects = [self localObjectsFromFetchRequestsMatchingRequestURL:error];
743+
NSSet *localObjects = [self localObjectsFromFetchRequests:fetchRequests matchingRequestURL:error];
721744
if (! localObjects) {
722745
RKLogError(@"Failed when attempting to fetch local candidate objects for orphan cleanup: %@", error ? *error : nil);
723746
return NO;

Code/Network/RKObjectRequestOperation.m

+5-4
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ - (void)objectRequestOperationDidStart:(NSNotification *)notification
151151
// Weakly tag the HTTP operation with its parent object request operation
152152
RKObjectRequestOperation *objectRequestOperation = [notification object];
153153
objc_setAssociatedObject(objectRequestOperation, RKOperationStartDate, [NSDate date], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
154-
objc_setAssociatedObject(objectRequestOperation.HTTPRequestOperation, RKParentObjectRequestOperation, objectRequestOperation, OBJC_ASSOCIATION_ASSIGN);
154+
objc_setAssociatedObject(objectRequestOperation.HTTPRequestOperation, RKParentObjectRequestOperation, objectRequestOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
155155
}
156156

157157
- (void)HTTPOperationDidStart:(NSNotification *)notification
@@ -165,9 +165,9 @@ - (void)HTTPOperationDidStart:(NSNotification *)notification
165165
NSString *body = nil;
166166
if ([operation.request HTTPBody]) {
167167
body = RKLogTruncateString([[NSString alloc] initWithData:[operation.request HTTPBody] encoding:NSUTF8StringEncoding]);
168-
} else if ([operation.request HTTPBodyStream]) {
168+
} /*else if ([operation.request HTTPBodyStream]) {
169169
body = RKStringDescribingStream([operation.request HTTPBodyStream]);
170-
}
170+
}*/
171171

172172
RKLogTrace(@"%@ '%@':\nrequest.headers=%@\nrequest.body=%@", [operation.request HTTPMethod], [[operation.request URL] absoluteString], [operation.request allHTTPHeaderFields], body);
173173
} else {
@@ -182,6 +182,7 @@ - (void)HTTPOperationDidFinish:(NSNotification *)notification
182182

183183
// NOTE: if we have a parent object request operation, we'll wait it to finish to emit the logging info
184184
RKObjectRequestOperation *parentOperation = objc_getAssociatedObject(operation, RKParentObjectRequestOperation);
185+
objc_setAssociatedObject(operation, RKParentObjectRequestOperation, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
185186
if (parentOperation) {
186187
objc_setAssociatedObject(operation, RKOperationFinishDate, [NSDate date], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
187188
return;
@@ -604,7 +605,7 @@ - (BOOL)isConcurrent
604605

605606
- (BOOL)isReady
606607
{
607-
return [self.stateMachine isReady];
608+
return [self.stateMachine isReady] && [super isReady];
608609
}
609610

610611
- (BOOL)isExecuting

Code/ObjectMapping/RKMapperOperation.m

+6-8
Original file line numberDiff line numberDiff line change
@@ -397,11 +397,7 @@ - (void)main
397397
BOOL foundMappable = NO;
398398
NSMutableDictionary *results = [self mapSourceRepresentationWithMappingsDictionary:self.mappingsDictionary];
399399
if ([self isCancelled]) return;
400-
foundMappable = (results != nil);
401-
402-
if ([self.delegate respondsToSelector:@selector(mapperDidFinishMapping:)]) {
403-
[self.delegate mapperDidFinishMapping:self];
404-
}
400+
foundMappable = (results != nil);
405401

406402
// If we found nothing eligible for mapping in the content, add an unmappable key path error and fail mapping
407403
// If the content is empty, we don't consider it an error
@@ -413,12 +409,14 @@ - (void)main
413409
RKDetailedErrorsKey: self.errors} mutableCopy];
414410
NSError *compositeError = [[NSError alloc] initWithDomain:RKErrorDomain code:RKMappingErrorNotFound userInfo:userInfo];
415411
self.error = compositeError;
416-
return;
412+
} else {
413+
if (results) self.mappingResult = [[RKMappingResult alloc] initWithDictionary:results];
417414
}
418415

419416
RKLogDebug(@"Finished performing object mapping. Results: %@", results);
420-
421-
if (results) self.mappingResult = [[RKMappingResult alloc] initWithDictionary:results];
417+
if ([self.delegate respondsToSelector:@selector(mapperDidFinishMapping:)]) {
418+
[self.delegate mapperDidFinishMapping:self];
419+
}
422420
}
423421

424422
- (BOOL)execute:(NSError **)error

Code/ObjectMapping/RKMappingOperation.h

+6-3
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,12 @@
160160
NSDictionary *representation = @{ @"name": @"Blake Watters" };
161161
NSDictionary *metadata = @{ @"URL": [NSURL URLWithString:@"http://restkit.org"] };
162162
163-
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKMetadataExample class]];
164-
[mapping addAttributeMappingsFromDicitonary:@{ @"name": @"name", @"@metadata.URL": @"URL" }];
165-
RKMappingOperation *mappingOperation = [[RKObjectMapping alloc] initWithSourceObject:representation destinationObject:example mapping:
163+
RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[RKMetadataExample class]];
164+
[objectMapping addAttributeMappingsFromDictionary:@{ @"name": @"name", @"@metadata.URL": @"URL" }];
165+
166+
RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:representation destinationObject:example mapping:objectMapping];
167+
mappingOperation.metadata = metadata;
168+
166169
NSError *error = nil;
167170
BOOL success = [mappingOperation execute:&error];
168171

Code/ObjectMapping/RKMappingOperation.m

+7-1
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,14 @@ id RKTransformedValueWithClass(id value, Class destinationType, NSValueTransform
117117
if ([booleanStrings containsObject:lowercasedString]) {
118118
// Handle booleans encoded as Strings
119119
return [NSNumber numberWithBool:[trueStrings containsObject:lowercasedString]];
120-
} else {
120+
} else if ([(NSString *)value rangeOfString:@"."].location != NSNotFound) {
121+
// String -> Floating Point Number
122+
// Only use floating point if needed to avoid losing precision
123+
// on large integers
121124
return [NSNumber numberWithDouble:[(NSString *)value doubleValue]];
125+
} else {
126+
// String -> Signed Integer
127+
return [NSNumber numberWithLongLong:[(NSString *)value longLongValue]];
122128
}
123129
}
124130
} else if ([value isEqual:[NSNull null]]) {

Code/ObjectMapping/RKObjectUtilities.m

+26-26
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
//
2020

2121
#import <objc/message.h>
22+
#import <objc/runtime.h>
2223
#import "RKObjectUtilities.h"
2324

2425
BOOL RKObjectIsEqualToObject(id object, id anotherObject) {
@@ -84,9 +85,8 @@ BOOL RKObjectIsCollectionOfCollections(id object)
8485
Class RKKeyValueCodingClassForObjCType(const char *type)
8586
{
8687
if (type) {
87-
// https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
8888
switch (type[0]) {
89-
case '@': {
89+
case _C_ID: {
9090
char *openingQuoteLoc = strchr(type, '"');
9191
if (openingQuoteLoc) {
9292
char *closingQuoteLoc = strchr(openingQuoteLoc+1, '"');
@@ -102,38 +102,38 @@ Class RKKeyValueCodingClassForObjCType(const char *type)
102102
// If there is no quoted class type (id), it can be used as-is.
103103
return Nil;
104104
}
105-
106-
case 'c': // char
107-
case 'C': // unsigned char
108-
case 's': // short
109-
case 'S': // unsigned short
110-
case 'i': // int
111-
case 'I': // unsigned int
112-
case 'l': // long
113-
case 'L': // unsigned long
114-
case 'q': // long long
115-
case 'Q': // unsigned long long
116-
case 'f': // float
117-
case 'd': // double
105+
106+
case _C_CHR: // char
107+
case _C_UCHR: // unsigned char
108+
case _C_SHT: // short
109+
case _C_USHT: // unsigned short
110+
case _C_INT: // int
111+
case _C_UINT: // unsigned int
112+
case _C_LNG: // long
113+
case _C_ULNG: // unsigned long
114+
case _C_LNG_LNG: // long long
115+
case _C_ULNG_LNG: // unsigned long long
116+
case _C_FLT: // float
117+
case _C_DBL: // double
118118
return [NSNumber class];
119119

120-
case 'B': // C++ bool or C99 _Bool
120+
case _C_BOOL: // C++ bool or C99 _Bool
121121
return objc_getClass("NSCFBoolean")
122122
?: objc_getClass("__NSCFBoolean")
123123
?: [NSNumber class];
124124

125-
case '{': // struct
126-
case 'b': // bitfield
127-
case '(': // union
125+
case _C_STRUCT_B: // struct
126+
case _C_BFLD: // bitfield
127+
case _C_UNION_B: // union
128128
return [NSValue class];
129129

130-
case '[': // c array
131-
case '^': // pointer
132-
case 'v': // void
133-
case '*': // char *
134-
case '#': // Class
135-
case ':': // selector
136-
case '?': // unknown type (function pointer, etc)
130+
case _C_ARY_B: // c array
131+
case _C_PTR: // pointer
132+
case _C_VOID: // void
133+
case _C_CHARPTR: // char *
134+
case _C_CLASS: // Class
135+
case _C_SEL: // selector
136+
case _C_UNDEF: // unknown type (function pointer, etc)
137137
default:
138138
break;
139139
}

Code/Support/RKMIMETypeSerialization.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ + (void)unregisterClass:(Class<RKSerialization>)serializationClass
133133
{
134134
NSArray *registrationsCopy = [[self sharedSerialization].registrations copy];
135135
for (RKMIMETypeSerializationRegistration *registration in registrationsCopy) {
136-
if (registration.class == serializationClass) {
136+
if (registration.serializationClass == serializationClass) {
137137
[[self sharedSerialization].registrations removeObject:registration];
138138
}
139139
}

Code/Support/RKOperationStateMachine.m

+2-3
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,7 @@ - (id)initWithOperation:(NSOperation *)operation dispatchQueue:(dispatch_queue_t
6868
[executingState setWillEnterStateBlock:^(TKState *state, TKStateMachine *stateMachine) {
6969
[self.operation willChangeValueForKey:@"isExecuting"];
7070
}];
71-
[executingState setDidEnterStateBlock:^(TKState *state, TKStateMachine *stateMachine) {
72-
[self.operation didChangeValueForKey:@"isExecuting"];
73-
}];
71+
// NOTE: isExecuting KVO for `setDidEnterStateBlock:` configured below in `setExecutionBlock`
7472
[executingState setWillExitStateBlock:^(TKState *state, TKStateMachine *stateMachine) {
7573
[self.operation willChangeValueForKey:@"isExecuting"];
7674
}];
@@ -172,6 +170,7 @@ - (void)setExecutionBlock:(void (^)(void))block
172170
{
173171
TKState *executingState = [self.stateMachine stateNamed:RKOperationStateExecuting];
174172
[executingState setDidEnterStateBlock:^(TKState *state, TKStateMachine *stateMachine) {
173+
[self.operation didChangeValueForKey:@"isExecuting"];
175174
dispatch_async(self.dispatchQueue, ^{
176175
block();
177176
});

Examples/RKTwitterCoreData/Classes/RKTwitterAppDelegate.m

+5-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,11 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
8888
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelInfo);
8989
RKLogConfigureByName("RestKit/CoreData", RKLogLevelTrace);
9090

91-
NSError *error;
91+
NSError *error = nil;
92+
BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error);
93+
if (! success) {
94+
RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error);
95+
}
9296
NSString *seedStorePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"RKSeedDatabase.sqlite"];
9397
RKManagedObjectImporter *importer = [[RKManagedObjectImporter alloc] initWithManagedObjectModel:managedObjectModel storePath:seedStorePath];
9498
[importer importObjectsFromItemAtPath:[[NSBundle mainBundle] pathForResource:@"restkit" ofType:@"json"]

Gemfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ gem "bundler", "~> 1.3.0"
55
gem "sinatra", :git => "git://github.com/sinatra/sinatra.git"
66
gem "thin", "~> 1.5.0"
77
gem 'debugger', '~> 1.3.0'
8-
gem 'cocoapods', '0.19.1'
8+
gem 'cocoapods', '0.20.2'
99
gem 'rakeup', '~> 1.0.0'

Gemfile.lock

+14-14
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,24 @@ GEM
1414
i18n (= 0.6.1)
1515
multi_json (~> 1.0)
1616
addressable (2.3.4)
17-
claide (0.2.0)
18-
cocoapods (0.19.1)
17+
claide (0.3.2)
18+
cocoapods (0.20.2)
1919
activesupport (~> 3.2.13)
20-
claide (~> 0.2.0)
21-
cocoapods-core (= 0.19.1)
22-
cocoapods-downloader (~> 0.1.0)
20+
claide (~> 0.3.2)
21+
cocoapods-core (= 0.20.2)
22+
cocoapods-downloader (~> 0.1.1)
2323
colored (~> 1.2)
2424
escape (~> 0.0.4)
2525
faraday (~> 0.8.1)
26-
json (~> 1.7.3)
26+
json (~> 1.8.0)
2727
octokit (~> 1.7)
2828
open4 (~> 1.3.0)
2929
rake (~> 10.0.0)
30-
xcodeproj (~> 0.5.5)
31-
cocoapods-core (0.19.1)
30+
xcodeproj (~> 0.6.0)
31+
cocoapods-core (0.20.2)
3232
activesupport (~> 3.2.13)
3333
rake (~> 10.0.0)
34-
cocoapods-downloader (0.1.0)
34+
cocoapods-downloader (0.1.1)
3535
colored (1.2)
3636
columnize (0.3.6)
3737
daemons (1.1.9)
@@ -48,10 +48,10 @@ GEM
4848
multipart-post (~> 1.1)
4949
faraday_middleware (0.9.0)
5050
faraday (>= 0.7.4, < 0.9)
51-
hashie (2.0.4)
51+
hashie (2.0.5)
5252
i18n (0.6.1)
53-
json (1.7.7)
54-
multi_json (1.7.3)
53+
json (1.8.0)
54+
multi_json (1.7.4)
5555
multipart-post (1.2.0)
5656
netrc (0.7.7)
5757
octokit (1.24.0)
@@ -74,7 +74,7 @@ GEM
7474
eventmachine (>= 0.12.6)
7575
rack (>= 1.0.0)
7676
tilt (1.4.0)
77-
xcodeproj (0.5.5)
77+
xcodeproj (0.6.0)
7878
activesupport (~> 3.2.13)
7979
colored (~> 1.2)
8080

@@ -83,7 +83,7 @@ PLATFORMS
8383

8484
DEPENDENCIES
8585
bundler (~> 1.3.0)
86-
cocoapods (= 0.19.1)
86+
cocoapods (= 0.20.2)
8787
debugger (~> 1.3.0)
8888
rake (~> 10.0.0)
8989
rakeup (~> 1.0.0)

Podfile.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ SPEC CHECKSUMS:
1616
OCMock: 79212e5e328378af5cfd6edb5feacfd6c49cd8a3
1717
Specta: 8a215d36842f2d29e888786937d1bf7f8725f780
1818

19-
COCOAPODS: 0.19.1
19+
COCOAPODS: 0.20.2

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,9 @@ RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWith
257257
[operation setCompletionBlockWithSuccess:nil failure:^(RKObjectRequestOperation *operation, NSError *error) {
258258
// The `description` method of the class the error is mapped to is used to construct the value of the localizedDescription
259259
NSLog(@"Loaded this error: %@", [error localizedDescription]);
260+
261+
// You can access the model object used to construct the `NSError` via the `userInfo`
262+
RKErrorMessage *errorMessage = [[error.userInfo objectForKey:RKObjectMapperErrorObjectsKey] firstObject];
260263
}];
261264
```
262265

0 commit comments

Comments
 (0)