From 04493804766d350128340ebb2e714dd367bcdba4 Mon Sep 17 00:00:00 2001 From: Blake Watters Date: Thu, 6 Jan 2011 14:51:44 -0500 Subject: [PATCH 1/3] Fix deprecation warning in earlier change. Fixed a sequencing problem with the overloaded accessors on RKRequest --- Code/Network/RKRequest.m | 38 +++++++++++++++++------------------ Code/Network/RKRequestQueue.m | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Code/Network/RKRequest.m b/Code/Network/RKRequest.m index ba36f559..0ec6528b 100644 --- a/Code/Network/RKRequest.m +++ b/Code/Network/RKRequest.m @@ -64,11 +64,23 @@ [super dealloc]; } +- (void)setRequestBody { + if (_params) { + // Prefer the use of a stream over a raw body + if ([_params respondsToSelector:@selector(HTTPBodyStream)]) { + [_URLRequest setHTTPBodyStream:[_params HTTPBodyStream]]; + } else { + [_URLRequest setHTTPBody:[_params HTTPBody]]; + } + } +} + - (void)addHeadersToRequest { NSString* header; for (header in _additionalHTTPHeaders) { [_URLRequest setValue:[_additionalHTTPHeaders valueForKey:header] forHTTPHeaderField:header]; } + if (_params != nil) { // Temporarily support older RKRequestSerializable implementations if ([_params respondsToSelector:@selector(HTTPHeaderValueForContentType)]) { @@ -80,6 +92,7 @@ [_URLRequest setValue:[NSString stringWithFormat:@"%d", [_params HTTPHeaderValueForContentLength]] forHTTPHeaderField:@"Content-Length"]; } } + if (_username != nil) { // Add authentication headers so we don't have to deal with an extra cycle for each message requiring basic auth. CFHTTPMessageRef dummyRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)[self HTTPMethod], (CFURLRef)[self URL], kCFHTTPVersion1_1); @@ -94,24 +107,11 @@ NSLog(@"Headers: %@", [_URLRequest allHTTPHeaderFields]); } -- (void)setMethod:(RKRequestMethod)method { - _method = method; +// Setup the NSURLRequest. The request must be prepared right before dispatching +- (void)prepareURLRequest { [_URLRequest setHTTPMethod:[self HTTPMethod]]; -} - -- (void)setParams:(NSObject*)params { - [params retain]; - [_params release]; - _params = params; - - if (params && ![self isGET]) { - // Prefer the use of a stream over a raw body - if ([_params respondsToSelector:@selector(HTTPBodyStream)]) { - [_URLRequest setHTTPBodyStream:[_params HTTPBodyStream]]; - } else { - [_URLRequest setHTTPBody:[_params HTTPBody]]; - } - } + [self setRequestBody]; + [self addHeadersToRequest]; } - (NSString*)HTTPMethod { @@ -140,7 +140,7 @@ - (void)fireAsynchronousRequest { if ([[RKClient sharedClient] isNetworkAvailable]) { - [self addHeadersToRequest]; + [self prepareURLRequest]; NSString* body = [[NSString alloc] initWithData:[_URLRequest HTTPBody] encoding:NSUTF8StringEncoding]; NSLog(@"Sending %@ request to URL %@. HTTP Body: %@", [self HTTPMethod], [[self URL] absoluteString], body); [body release]; @@ -168,7 +168,7 @@ RKResponse* response = nil; if ([[RKClient sharedClient] isNetworkAvailable]) { - [self addHeadersToRequest]; + [self prepareURLRequest]; NSString* body = [[NSString alloc] initWithData:[_URLRequest HTTPBody] encoding:NSUTF8StringEncoding]; NSLog(@"Sending synchronous %@ request to URL %@. HTTP Body: %@", [self HTTPMethod], [[self URL] absoluteString], body); [body release]; diff --git a/Code/Network/RKRequestQueue.m b/Code/Network/RKRequestQueue.m index 17473dd8..e913ffe3 100644 --- a/Code/Network/RKRequestQueue.m +++ b/Code/Network/RKRequestQueue.m @@ -76,7 +76,7 @@ static const NSInteger kMaxConcurrentLoads = 5; - (void)loadNextInQueue { // This makes sure that the Request Queue does not fire off any requests until the Reachability state has been determined. // This prevents the request queue from - if ([[[RKClient client] baseURLReachabilityObserver] networkStatus] == RKReachabilityIndeterminate) { + if ([[[RKClient sharedClient] baseURLReachabilityObserver] networkStatus] == RKReachabilityIndeterminate) { [self loadNextInQueueDelayed]; return; } From 88489747e8bf5d883a11a96d3cd8acb142271257 Mon Sep 17 00:00:00 2001 From: Jeff Arena Date: Thu, 6 Jan 2011 11:55:43 -0800 Subject: [PATCH 2/3] add additional response convenience method for checking for a 503 response code; quiet a compiler warning regarding depracated client class method; add default support for generating a uialertview when restkit encounters a 503 response; added ability to turn 503 error on/off, as well as ability to customize the alert --- Code/Network/RKClient.h | 24 ++++++++ Code/Network/RKClient.m | 14 ++++- Code/Network/RKRequest.m | 50 ++++++++++------- Code/Network/RKRequestQueue.m | 40 +++++++------- Code/Network/RKResponse.h | 5 ++ Code/Network/RKResponse.m | 4 ++ Code/ObjectMapping/RKObjectLoader.m | 85 +++++++++++++++++------------ 7 files changed, 145 insertions(+), 77 deletions(-) diff --git a/Code/Network/RKClient.h b/Code/Network/RKClient.h index 0e30c14c..31af72fa 100644 --- a/Code/Network/RKClient.h +++ b/Code/Network/RKClient.h @@ -47,6 +47,9 @@ NSString* RKMakeURLPath(NSString* resourcePath); NSString* _password; NSMutableDictionary* _HTTPHeaders; RKReachabilityObserver* _baseURLReachabilityObserver; + NSString* _serviceUnavailableAlertTitle; + NSString* _serviceUnavailableAlertMessage; + BOOL _serviceUnavailableAlertEnabled; } /** @@ -75,6 +78,27 @@ NSString* RKMakeURLPath(NSString* resourcePath); */ @property(nonatomic, readonly) RKReachabilityObserver* baseURLReachabilityObserver; +/** + * The title to use in the UIAlertView shown when a request encounters a + * ServiceUnavailable (503) response. + * If not provided, the default is: "Service Unavailable" + */ +@property(nonatomic, retain) NSString* serviceUnavailableAlertTitle; + +/** + * The message to use in the UIAlertView shown when a request encounters a + * ServiceUnavailable (503) response. + * If not provided, the default is: "The remote resource is unavailable. Please try again later." + */ +@property(nonatomic, retain) NSString* serviceUnavailableAlertMessage; + +/** + * Flag that determines whether the Service Unavailable alert is shown in response + * to a ServiceUnavailable (503) response. + * Defaults to NO. + */ +@property(nonatomic, assign) BOOL serviceUnavailableAlertEnabled; + /** * Return the configured singleton instance of the Rest client */ diff --git a/Code/Network/RKClient.m b/Code/Network/RKClient.m index b01f7b10..6acbb85b 100644 --- a/Code/Network/RKClient.m +++ b/Code/Network/RKClient.m @@ -36,6 +36,9 @@ NSString* RKMakeURLPath(NSString* resourcePath) { @synthesize password = _password; @synthesize HTTPHeaders = _HTTPHeaders; @synthesize baseURLReachabilityObserver = _baseURLReachabilityObserver; +@synthesize serviceUnavailableAlertTitle = _serviceUnavailableAlertTitle; +@synthesize serviceUnavailableAlertMessage = _serviceUnavailableAlertMessage; +@synthesize serviceUnavailableAlertEnabled = _serviceUnavailableAlertEnabled; + (RKClient*)sharedClient { return sharedClient; @@ -78,15 +81,20 @@ NSString* RKMakeURLPath(NSString* resourcePath) { - (id)init { if (self = [super init]) { _HTTPHeaders = [[NSMutableDictionary alloc] init]; + self.serviceUnavailableAlertEnabled = NO; + self.serviceUnavailableAlertTitle = NSLocalizedString(@"Service Unavailable", nil); + self.serviceUnavailableAlertMessage = NSLocalizedString(@"The remote resource is unavailable. Please try again later.", nil); } return self; } - (void)dealloc { - [_baseURL release]; - [_username release]; - [_password release]; + self.baseURL = nil; + self.username = nil; + self.password = nil; + self.serviceUnavailableAlertTitle = nil; + self.serviceUnavailableAlertTitle = nil; [_HTTPHeaders release]; [super dealloc]; } diff --git a/Code/Network/RKRequest.m b/Code/Network/RKRequest.m index ba36f559..19897389 100644 --- a/Code/Network/RKRequest.m +++ b/Code/Network/RKRequest.m @@ -14,6 +14,7 @@ #import "RKClient.h" #import "../Support/Support.h" #import "RKURL.h" +#import @implementation RKRequest @@ -75,7 +76,7 @@ [_URLRequest setValue:[_params HTTPHeaderValueForContentType] forHTTPHeaderField:@"Content-Type"]; } else if ([_params respondsToSelector:@selector(ContentTypeHTTPHeader)]) { [_URLRequest setValue:[_params performSelector:@selector(ContentTypeHTTPHeader)] forHTTPHeaderField:@"Content-Type"]; - } + } if ([_params respondsToSelector:@selector(HTTPHeaderValueForContentLength)]) { [_URLRequest setValue:[NSString stringWithFormat:@"%d", [_params HTTPHeaderValueForContentLength]] forHTTPHeaderField:@"Content-Length"]; } @@ -85,9 +86,9 @@ CFHTTPMessageRef dummyRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)[self HTTPMethod], (CFURLRef)[self URL], kCFHTTPVersion1_1); CFHTTPMessageAddAuthentication(dummyRequest, nil, (CFStringRef)_username, (CFStringRef)_password, kCFHTTPAuthenticationSchemeBasic, FALSE); CFStringRef authorizationString = CFHTTPMessageCopyHeaderFieldValue(dummyRequest, CFSTR("Authorization")); - + [_URLRequest setValue:(NSString *)authorizationString forHTTPHeaderField:@"Authorization"]; - + CFRelease(dummyRequest); CFRelease(authorizationString); } @@ -103,11 +104,11 @@ [params retain]; [_params release]; _params = params; - + if (params && ![self isGET]) { // Prefer the use of a stream over a raw body - if ([_params respondsToSelector:@selector(HTTPBodyStream)]) { - [_URLRequest setHTTPBodyStream:[_params HTTPBodyStream]]; + if ([_params respondsToSelector:@selector(HTTPBodyStream)]) { + [_URLRequest setHTTPBodyStream:[_params HTTPBodyStream]]; } else { [_URLRequest setHTTPBody:[_params HTTPBody]]; } @@ -147,7 +148,7 @@ NSDate* sentAt = [NSDate date]; NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", [self URL], @"URL", sentAt, @"sentAt", nil]; [[NSNotificationCenter defaultCenter] postNotificationName:kRKRequestSentNotification object:self userInfo:userInfo]; - + _isLoading = YES; RKResponse* response = [[[RKResponse alloc] initWithRequest:self] autorelease]; _connection = [[NSURLConnection connectionWithRequest:_URLRequest delegate:response] retain]; @@ -156,7 +157,7 @@ NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys: errorMessage, NSLocalizedDescriptionKey, nil]; - NSError* error = [NSError errorWithDomain:RKRestKitErrorDomain code:RKRequestBaseURLOfflineError userInfo:userInfo]; + NSError* error = [NSError errorWithDomain:RKRestKitErrorDomain code:RKRequestBaseURLOfflineError userInfo:userInfo]; [self didFailLoadWithError:error]; } } @@ -166,7 +167,7 @@ NSError* error = nil; NSData* payload = nil; RKResponse* response = nil; - + if ([[RKClient sharedClient] isNetworkAvailable]) { [self addHeadersToRequest]; NSString* body = [[NSString alloc] initWithData:[_URLRequest HTTPBody] encoding:NSUTF8StringEncoding]; @@ -175,7 +176,7 @@ NSDate* sentAt = [NSDate date]; NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", [self URL], @"URL", sentAt, @"sentAt", nil]; [[NSNotificationCenter defaultCenter] postNotificationName:kRKRequestSentNotification object:self userInfo:userInfo]; - + _isLoading = YES; payload = [NSURLConnection sendSynchronousRequest:_URLRequest returningResponse:&URLResponse error:&error]; response = [[[RKResponse alloc] initWithSynchronousRequest:self URLResponse:URLResponse body:payload error:error] autorelease]; @@ -186,11 +187,11 @@ nil]; error = [NSError errorWithDomain:RKRestKitErrorDomain code:RKRequestBaseURLOfflineError userInfo:userInfo]; [self didFailLoadWithError:error]; - + // TODO: Is this needed here? Or can we just return a nil response and everyone will be happy?? response = [[[RKResponse alloc] initWithSynchronousRequest:self URLResponse:URLResponse body:payload error:error] autorelease]; } - + return response; } @@ -203,28 +204,39 @@ - (void)didFailLoadWithError:(NSError*)error { _isLoading = NO; - + if ([_delegate respondsToSelector:@selector(request:didFailLoadWithError:)]) { [_delegate request:self didFailLoadWithError:error]; } - + NSDate* receivedAt = [NSDate date]; - NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", + NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", [self URL], @"URL", receivedAt, @"receivedAt", error, @"error", nil]; - [[NSNotificationCenter defaultCenter] postNotificationName:kRKRequestFailedWithErrorNotification object:self userInfo:userInfo]; + [[NSNotificationCenter defaultCenter] postNotificationName:kRKRequestFailedWithErrorNotification object:self userInfo:userInfo]; } - (void)didFinishLoad:(RKResponse*)response { _isLoading = NO; _isLoaded = YES; - + if ([_delegate respondsToSelector:@selector(request:didLoadResponse:)]) { [_delegate request:self didLoadResponse:response]; } - + NSDate* receivedAt = [NSDate date]; NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", [self URL], @"URL", receivedAt, @"receivedAt", nil]; - [[NSNotificationCenter defaultCenter] postNotificationName:kRKResponseReceivedNotification object:response userInfo:userInfo]; + [[NSNotificationCenter defaultCenter] postNotificationName:kRKResponseReceivedNotification object:response userInfo:userInfo]; + + if ([response isServiceUnavailable] && [[RKClient sharedClient] serviceUnavailableAlertEnabled]) { + UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:[[RKClient sharedClient] serviceUnavailableAlertTitle] + message:[[RKClient sharedClient] serviceUnavailableAlertMessage] + delegate:nil + cancelButtonTitle:NSLocalizedString(@"OK", nil) + otherButtonTitles:nil]; + [alertView show]; + [alertView release]; + + } } - (BOOL)isGET { diff --git a/Code/Network/RKRequestQueue.m b/Code/Network/RKRequestQueue.m index 17473dd8..550f8ba6 100644 --- a/Code/Network/RKRequestQueue.m +++ b/Code/Network/RKRequestQueue.m @@ -40,14 +40,14 @@ static const NSInteger kMaxConcurrentLoads = 5; _requests = [[NSMutableArray alloc] init]; _suspended = NO; _totalLoading = 0; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(responseDidLoad:) - name:kRKResponseReceivedNotification + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(responseDidLoad:) + name:kRKResponseReceivedNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(responseDidLoad:) + name:kRKRequestFailedWithErrorNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(responseDidLoad:) - name:kRKRequestFailedWithErrorNotification - object:nil]; } return self; } @@ -61,10 +61,10 @@ static const NSInteger kMaxConcurrentLoads = 5; - (void)loadNextInQueueDelayed { if (!_queueTimer) { - _queueTimer = [NSTimer scheduledTimerWithTimeInterval:kFlushDelay + _queueTimer = [NSTimer scheduledTimerWithTimeInterval:kFlushDelay target:self - selector:@selector(loadNextInQueue) - userInfo:nil + selector:@selector(loadNextInQueue) + userInfo:nil repeats:NO]; } } @@ -75,21 +75,21 @@ static const NSInteger kMaxConcurrentLoads = 5; - (void)loadNextInQueue { // This makes sure that the Request Queue does not fire off any requests until the Reachability state has been determined. - // This prevents the request queue from - if ([[[RKClient client] baseURLReachabilityObserver] networkStatus] == RKReachabilityIndeterminate) { + // This prevents the request queue from + if ([[[RKClient sharedClient] baseURLReachabilityObserver] networkStatus] == RKReachabilityIndeterminate) { [self loadNextInQueueDelayed]; return; } - + _queueTimer = nil; - + for (RKRequest* request in _requests) { if (![request isLoading] && ![request isLoaded] && _totalLoading < kMaxConcurrentLoads) { ++_totalLoading; [self dispatchRequest:request]; } } - + if (_requests.count && !_suspended) { [self loadNextInQueueDelayed]; } @@ -97,7 +97,7 @@ static const NSInteger kMaxConcurrentLoads = 5; - (void)setSuspended:(BOOL)isSuspended { _suspended = isSuspended; - + if (!_suspended) { [self loadNextInQueue]; } else if (_queueTimer) { @@ -115,10 +115,10 @@ static const NSInteger kMaxConcurrentLoads = 5; if ([_requests containsObject:request] && ![request isLoaded]) { [request cancel]; request.delegate = nil; - + [_requests removeObject:request]; _totalLoading--; - + if (loadNext) { [self loadNextInQueue]; } @@ -156,14 +156,14 @@ static const NSInteger kMaxConcurrentLoads = 5; RKRequest* request = [(RKResponse*)notification.object request]; [_requests removeObject:request]; _totalLoading--; - + // Our RKRequest failed and we're notified with the original RKRequest object } else if ([notification.object isKindOfClass:[RKRequest class]]) { RKRequest* request = (RKRequest*)notification.object; [_requests removeObject:request]; _totalLoading--; } - + [self loadNextInQueue]; } } diff --git a/Code/Network/RKResponse.h b/Code/Network/RKResponse.h index 3309f0a2..7b093d7e 100644 --- a/Code/Network/RKResponse.h +++ b/Code/Network/RKResponse.h @@ -168,6 +168,11 @@ */ - (BOOL)isEmpty; +/** + * Indicates an HTTP response code of 503 + */ +- (BOOL)isServiceUnavailable; + /** * Returns the value of 'Content-Type' HTTP header */ diff --git a/Code/Network/RKResponse.m b/Code/Network/RKResponse.m index e15d6ca9..2395f076 100644 --- a/Code/Network/RKResponse.m +++ b/Code/Network/RKResponse.m @@ -203,6 +203,10 @@ return ([self statusCode] == 201 || [self statusCode] == 204 || [self statusCode] == 304); } +- (BOOL)isServiceUnavailable { + return ([self statusCode] == 503); +} + - (NSString*)contentType { return ([[self allHeaderFields] objectForKey:@"Content-Type"]); } diff --git a/Code/ObjectMapping/RKObjectLoader.m b/Code/ObjectMapping/RKObjectLoader.m index cfe691b4..705ddca1 100644 --- a/Code/ObjectMapping/RKObjectLoader.m +++ b/Code/ObjectMapping/RKObjectLoader.m @@ -14,6 +14,7 @@ #import "RKManagedObject.h" #import "RKURL.h" #import "RKNotifications.h" +#import @implementation RKObjectLoader @@ -29,7 +30,7 @@ _mapper = [mapper retain]; self.managedObjectStore = nil; _targetObjectID = nil; - + [[RKClient sharedClient] setupRequest:self]; } return self; @@ -45,7 +46,7 @@ [_targetObject release]; _targetObject = nil; [_targetObjectID release]; - _targetObjectID = nil; + _targetObjectID = nil; self.managedObjectStore = nil; [super dealloc]; } @@ -54,10 +55,10 @@ [_targetObject release]; _targetObject = nil; _targetObject = [targetObject retain]; - + [_targetObjectID release]; _targetObjectID = nil; - + if ([targetObject isKindOfClass:[NSManagedObject class]]) { _targetObjectID = [[(NSManagedObject*)targetObject objectID] retain]; } @@ -68,10 +69,10 @@ - (void)responseProcessingSuccessful:(BOOL)successful withError:(NSError*)error { _isLoading = NO; - + NSDate* receivedAt = [NSDate date]; if (successful) { - _isLoaded = YES; + _isLoaded = YES; NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", [self URL], @"URL", receivedAt, @"receivedAt", @@ -80,7 +81,7 @@ object:_response userInfo:userInfo]; } else { - NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", + NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", [self URL], @"URL", receivedAt, @"receivedAt", error, @"error", @@ -94,16 +95,30 @@ - (BOOL)encounteredErrorWhileProcessingRequest:(RKResponse*)response { if ([response isFailure]) { [(NSObject*)_delegate objectLoader:self didFailWithError:response.failureError]; - + [self responseProcessingSuccessful:NO withError:response.failureError]; - + return YES; } else if ([response isError]) { NSError* error = nil; - + if ([response isJSON]) { error = [_mapper parseErrorFromString:[response bodyAsString]]; [(NSObject*)_delegate objectLoader:self didFailWithError:error]; + + } else if ([response isServiceUnavailable] && [[RKClient sharedClient] serviceUnavailableAlertEnabled]) { + if ([_delegate respondsToSelector:@selector(objectLoaderDidLoadUnexpectedResponse:)]) { + [(NSObject*)_delegate objectLoaderDidLoadUnexpectedResponse:self]; + } + + UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:[[RKClient sharedClient] serviceUnavailableAlertTitle] + message:[[RKClient sharedClient] serviceUnavailableAlertMessage] + delegate:nil + cancelButtonTitle:NSLocalizedString(@"OK", nil) + otherButtonTitles:nil]; + [alertView show]; + [alertView release]; + } else { // TODO: We've likely run into a maintenance page here. Consider adding the ability // to put the stack into offline mode in response... @@ -111,9 +126,9 @@ [(NSObject*)_delegate objectLoaderDidLoadUnexpectedResponse:self]; } } - + [self responseProcessingSuccessful:NO withError:error]; - + return YES; } return NO; @@ -122,7 +137,7 @@ - (void)informDelegateOfObjectLoadWithInfoDictionary:(NSDictionary*)dictionary { NSArray* models = [dictionary objectForKey:@"models"]; [dictionary release]; - + // NOTE: The models dictionary may contain NSManagedObjectID's from persistent objects // that were model mapped on a background thread. We look up the objects by ID and then // notify the delegate that the operation has completed. @@ -134,32 +149,32 @@ [objects addObject:object]; } } - + [(NSObject*)_delegate objectLoader:self didLoadObjects:[NSArray arrayWithArray:objects]]; - + [self responseProcessingSuccessful:YES withError:nil]; } - (void)informDelegateOfObjectLoadErrorWithInfoDictionary:(NSDictionary*)dictionary { NSError* error = [dictionary objectForKey:@"error"]; [dictionary release]; - + NSLog(@"[RestKit] RKObjectLoader: Error saving managed object context: error=%@ userInfo=%@", error, error.userInfo); - + NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys: [error localizedDescription], NSLocalizedDescriptionKey, - nil]; + nil]; NSError *rkError = [NSError errorWithDomain:RKRestKitErrorDomain code:RKObjectLoaderRemoteSystemError userInfo:userInfo]; - + [(NSObject*)_delegate objectLoader:self didFailWithError:rkError]; - + [self responseProcessingSuccessful:NO withError:rkError]; } - (void)processLoadModelsInBackground:(RKResponse *)response { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; RKManagedObjectStore* objectStore = self.managedObjectStore; - + /** * If this loader is bound to a particular object, then we map * the results back into the instance. This is used for loading and updating @@ -184,12 +199,12 @@ // so that in the event result is nil, then we get empty array instead of exception for trying to insert nil. results = [NSArray arrayWithObjects:result, nil]; } - + if (objectStore && [objectStore managedObjectCache]) { if ([self.URL isKindOfClass:[RKURL class]]) { RKURL* rkURL = (RKURL*)self.URL; NSArray* fetchRequests = [[objectStore managedObjectCache] fetchRequestsForResourcePath:rkURL.resourcePath]; - NSArray* cachedObjects = [RKManagedObject objectsWithFetchRequests:fetchRequests]; + NSArray* cachedObjects = [RKManagedObject objectsWithFetchRequests:fetchRequests]; for (id object in cachedObjects) { if ([object isKindOfClass:[RKManagedObject class]]) { if (NO == [results containsObject:object]) { @@ -200,15 +215,15 @@ } } } - + // Before looking up NSManagedObjectIDs, need to save to ensure we do not have // temporary IDs for new objects prior to handing the objectIDs across threads NSError* error = [objectStore save]; if (nil != error) { NSDictionary* infoDictionary = [[NSDictionary dictionaryWithObjectsAndKeys:response, @"response", error, @"error", nil] retain]; - [self performSelectorOnMainThread:@selector(informDelegateOfObjectLoadErrorWithInfoDictionary:) withObject:infoDictionary waitUntilDone:YES]; + [self performSelectorOnMainThread:@selector(informDelegateOfObjectLoadErrorWithInfoDictionary:) withObject:infoDictionary waitUntilDone:YES]; } else { - // NOTE: Passing Core Data objects across threads is not safe. + // NOTE: Passing Core Data objects across threads is not safe. // Iterate over each model and coerce Core Data objects into ID's to pass across the threads. // The object ID's will be deserialized back into objects on the main thread before the delegate is called back NSMutableArray* models = [NSMutableArray arrayWithCapacity:[results count]]; @@ -216,10 +231,10 @@ if ([object isKindOfClass:[NSManagedObject class]]) { [models addObject:[(NSManagedObject*)object objectID]]; } else { - [models addObject:object]; + [models addObject:object]; } - } - + } + NSDictionary* infoDictionary = [[NSDictionary dictionaryWithObjectsAndKeys:response, @"response", models, @"models", nil] retain]; [self performSelectorOnMainThread:@selector(informDelegateOfObjectLoadWithInfoDictionary:) withObject:infoDictionary waitUntilDone:YES]; } @@ -231,19 +246,19 @@ if ([_delegate respondsToSelector:@selector(request:didFailLoadWithError:)]) { [_delegate request:self didFailLoadWithError:error]; } - + [(NSObject*)_delegate objectLoader:self didFailWithError:error]; - + [self responseProcessingSuccessful:NO withError:error]; } - (void)didFinishLoad:(RKResponse*)response { _response = [response retain]; - + if ([_delegate respondsToSelector:@selector(request:didLoadResponse:)]) { [_delegate request:self didLoadResponse:response]; } - + if (NO == [self encounteredErrorWhileProcessingRequest:response]) { // TODO: When other mapping formats are supported, unwind this assumption... if ([response isSuccessful] && [response isJSON]) { @@ -252,7 +267,7 @@ NSLog(@"Encountered unexpected response code: %d (MIME Type: %@)", response.statusCode, response.MIMEType); if ([_delegate respondsToSelector:@selector(objectLoaderDidLoadUnexpectedResponse:)]) { [(NSObject*)_delegate objectLoaderDidLoadUnexpectedResponse:self]; - } + } [self responseProcessingSuccessful:NO withError:nil]; } } From c20062cb4ef47deb48410d6e16184c1df7b132b2 Mon Sep 17 00:00:00 2001 From: Jeff Arena Date: Thu, 6 Jan 2011 12:09:42 -0800 Subject: [PATCH 3/3] fixed a memory leak associated with the new 503 alert strings on the client --- Code/Network/RKClient.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Network/RKClient.m b/Code/Network/RKClient.m index 6acbb85b..b28b5af5 100644 --- a/Code/Network/RKClient.m +++ b/Code/Network/RKClient.m @@ -94,7 +94,7 @@ NSString* RKMakeURLPath(NSString* resourcePath) { self.username = nil; self.password = nil; self.serviceUnavailableAlertTitle = nil; - self.serviceUnavailableAlertTitle = nil; + self.serviceUnavailableAlertMessage = nil; [_HTTPHeaders release]; [super dealloc]; }