mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-24 12:55:58 +08:00
Move management of RKResponseHasBeenMapped to RKObjectRequestOperation instead of RKManagedObjectRequestOperation. Add unit tests.
This commit is contained in:
@@ -369,10 +369,11 @@ static NSURL *RKRelativeURLFromURLAndResponseDescriptors(NSURL *URL, NSArray *re
|
||||
[self.responseMapperOperation cancel];
|
||||
}
|
||||
|
||||
// RKResponseHasBeenMappedCacheUserInfoKey is stored by RKObjectRequestOperation
|
||||
- (BOOL)canSkipMapping
|
||||
{
|
||||
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:self.HTTPRequestOperation.request];
|
||||
return [[cachedResponse.userInfo objectForKey:@"RKResponseHasBeenMapped"] boolValue];
|
||||
return [[cachedResponse.userInfo objectForKey:RKResponseHasBeenMappedCacheUserInfoKey] boolValue];
|
||||
}
|
||||
|
||||
- (RKMappingResult *)performMappingOnResponse:(NSError **)error
|
||||
@@ -635,17 +636,7 @@ static NSURL *RKRelativeURLFromURLAndResponseDescriptors(NSURL *URL, NSArray *re
|
||||
if (! success || [self isCancelled]) {
|
||||
self.error = error;
|
||||
return;
|
||||
}
|
||||
|
||||
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:self.HTTPRequestOperation.request];
|
||||
if (cachedResponse) {
|
||||
// We're all done mapping this request. Now we set a flag on the cache entry's userInfo dictionary to indicate that the request
|
||||
// corresponding to the cache entry completed successfully, and we can reliably skip mapping if a subsequent request results
|
||||
// in the use of this cachedResponse.
|
||||
NSMutableDictionary *userInfo = cachedResponse.userInfo ? [cachedResponse.userInfo mutableCopy] : [NSMutableDictionary dictionaryWithObject:@YES forKey:@"RKResponseHasBeenMapped"];
|
||||
NSCachedURLResponse *newCachedResponse = [[NSCachedURLResponse alloc] initWithResponse:cachedResponse.response data:cachedResponse.data userInfo:userInfo storagePolicy:cachedResponse.storagePolicy];
|
||||
[[NSURLCache sharedURLCache] storeCachedResponse:newCachedResponse forRequest:self.HTTPRequestOperation.request];
|
||||
}
|
||||
}
|
||||
|
||||
// Refetch all managed objects nested at key paths within the results dictionary before returning
|
||||
if (self.mappingResult) {
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
#import "RKMappingResult.h"
|
||||
#import "RKMapperOperation.h"
|
||||
|
||||
/**
|
||||
The key for a Boolean NSNumber value that indicates if a `NSCachedURLResponse` stored in the `NSURLCache` has been object mapped to completion. This key is stored on the `userInfo` of the cached response, if any, just before an `RKObjectRequestOperation` transitions to the finished state.
|
||||
*/
|
||||
extern NSString * const RKResponseHasBeenMappedCacheUserInfoKey;
|
||||
|
||||
/**
|
||||
`RKObjectRequestOperation` is an `NSOperation` subclass that implements object mapping on the response body of an `NSHTTPResponse` loaded via an `RKHTTPRequestOperation`.
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
NSString * const RKObjectRequestOperationDidStartNotification = @"RKObjectRequestOperationDidStartNotification";
|
||||
NSString * const RKObjectRequestOperationDidFinishNotification = @"RKObjectRequestOperationDidFinishNotification";
|
||||
NSString * const RKResponseHasBeenMappedCacheUserInfoKey = @"RKResponseHasBeenMapped";
|
||||
|
||||
static void RKIncrementNetworkActivityIndicator()
|
||||
{
|
||||
@@ -315,8 +316,21 @@ static NSString *RKStringDescribingURLResponseWithData(NSURLResponse *response,
|
||||
}
|
||||
self.mappingResult = mappingResult;
|
||||
[self willFinish];
|
||||
|
||||
if (self.error) self.mappingResult = nil;
|
||||
|
||||
if (self.error) {
|
||||
self.mappingResult = nil;
|
||||
} else {
|
||||
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:self.HTTPRequestOperation.request];
|
||||
if (cachedResponse) {
|
||||
// We're all done mapping this request. Now we set a flag on the cache entry's userInfo dictionary to indicate that the request
|
||||
// corresponding to the cache entry completed successfully, and we can reliably skip mapping if a subsequent request results
|
||||
// in the use of this cachedResponse.
|
||||
NSMutableDictionary *userInfo = cachedResponse.userInfo ? [cachedResponse.userInfo mutableCopy] : [NSMutableDictionary dictionary];
|
||||
[userInfo setObject:@YES forKey:RKResponseHasBeenMappedCacheUserInfoKey];
|
||||
NSCachedURLResponse *newCachedResponse = [[NSCachedURLResponse alloc] initWithResponse:cachedResponse.response data:cachedResponse.data userInfo:userInfo storagePolicy:cachedResponse.storagePolicy];
|
||||
[[NSURLCache sharedURLCache] storeCachedResponse:newCachedResponse forRequest:self.HTTPRequestOperation.request];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)main
|
||||
|
||||
@@ -148,7 +148,7 @@ NSSet *RKSetByRemovingSubkeypathsFromSet(NSSet *setOfKeyPaths);
|
||||
}
|
||||
|
||||
// 304 'Not Modified'
|
||||
- (void)testThatManagedObjectsAreFetchedWhenHandlingANotModifiedResponse
|
||||
- (void)testThatManagedObjectsAreFetchedWhenHandlingAResponseThatCanSkipMapping
|
||||
{
|
||||
RKFetchRequestBlock fetchRequestBlock = ^(NSURL *URL){
|
||||
return [NSFetchRequest fetchRequestWithEntityName:@"Human"];
|
||||
@@ -156,7 +156,15 @@ NSSet *RKSetByRemovingSubkeypathsFromSet(NSSet *setOfKeyPaths);
|
||||
|
||||
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
|
||||
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext];
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/204_with_not_modified_status" relativeToURL:[RKTestFactory baseURL]]];
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/204" relativeToURL:[RKTestFactory baseURL]]];
|
||||
|
||||
// Store a cache entry indicating that the response has been previously mapped
|
||||
NSData *responseData = [@"{}" dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:[request URL] statusCode:200 HTTPVersion:@"1.1" headerFields:nil];
|
||||
NSAssert(response, @"Failed to build cached response");
|
||||
NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:responseData userInfo:@{RKResponseHasBeenMappedCacheUserInfoKey: @YES} storagePolicy:NSURLCacheStorageAllowed];
|
||||
[[NSURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:request];
|
||||
|
||||
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
|
||||
[humanMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]];
|
||||
|
||||
|
||||
@@ -112,6 +112,7 @@
|
||||
NSArray *validErrorCodes = @[ @(NSURLErrorCannotDecodeContentData), @(NSURLErrorCannotFindHost) ];
|
||||
assertThat(validErrorCodes, hasItem(@([requestOperation.error code])));
|
||||
}
|
||||
|
||||
- (void)testSendingAnObjectRequestOperationToAnBrokenURL
|
||||
{
|
||||
NSMutableURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://invalid••™¡.is"]];
|
||||
@@ -752,4 +753,38 @@
|
||||
expect(user.phone).to.equal(@"867-5309");
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)testThatCacheEntryIsFlaggedWhenMappingCompletes
|
||||
{
|
||||
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
|
||||
[userMapping addAttributeMappingsFromDictionary:@{ @"name": @"email" }];
|
||||
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping pathPattern:nil keyPath:@"human" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
|
||||
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/coredata/etag" relativeToURL:[RKTestFactory baseURL]]];
|
||||
RKObjectRequestOperation *requestOperation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
|
||||
[requestOperation start];
|
||||
expect(requestOperation.error).to.beNil();
|
||||
|
||||
NSCachedURLResponse *response = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
|
||||
expect(response).notTo.beNil();
|
||||
expect([response.userInfo valueForKey:RKResponseHasBeenMappedCacheUserInfoKey]).to.beTruthy();
|
||||
}
|
||||
|
||||
- (void)testThatCacheEntryIsNotFlaggedWhenMappingFails
|
||||
{
|
||||
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
|
||||
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping pathPattern:@"/mismatch" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
|
||||
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/coredata/etag" relativeToURL:[RKTestFactory baseURL]]];
|
||||
RKObjectRequestOperation *requestOperation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
|
||||
[requestOperation start];
|
||||
expect(requestOperation.error).notTo.beNil();
|
||||
expect([requestOperation.error localizedDescription]).to.equal(@"No response descriptors match the response loaded.");
|
||||
|
||||
NSCachedURLResponse *response = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
|
||||
expect(response).notTo.beNil();
|
||||
expect([response.userInfo valueForKey:RKResponseHasBeenMappedCacheUserInfoKey]).to.beFalsy();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -287,11 +287,6 @@ class RestKitTestServer < Sinatra::Base
|
||||
status 304
|
||||
end
|
||||
|
||||
get '/204_with_not_modified_status' do
|
||||
status 204
|
||||
response.headers['Status'] = '304 Not Modified'
|
||||
end
|
||||
|
||||
delete '/humans/1234/whitespace' do
|
||||
content_type 'application/json'
|
||||
status 200
|
||||
|
||||
Reference in New Issue
Block a user