Files
RestKit/Code/Three20/RKRequestModel.m
2010-10-19 14:21:39 -04:00

261 lines
7.0 KiB
Objective-C

//
// RKRequestModel.m
// RestKit
//
// Created by Jeff Arena on 4/26/10.
// Copyright 2010 RestKit. All rights reserved.
//
#import "RKRequestModel.h"
#import "RKManagedObjectStore.h"
#import <Three20/Three20.h>
@implementation RKRequestModel
@synthesize objects = _objects;
@synthesize loaded = _loaded;
@synthesize resourcePath = _resourcePath;
@synthesize params = _params;
@synthesize objectLoader = _objectLoader;
@synthesize method = _method;
@synthesize refreshRate = _refreshRate;
- (id)initWithResourcePath:(NSString*)resourcePath delegate:(id)delegate {
if (self = [self init]) {
_resourcePath = [resourcePath retain];
_delegate = [delegate retain];
}
[self loadFromObjectCache];
return self;
}
/**
* TODO: These initializers have to set the ivars so the state is configured before loadFromObjectCache is triggered.
* Do NOT DRY these up by adding dependencies or loadFromObjectCache will fire too early.
*
* WARNING
*/
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params delegate:(id)delegate {
if (self = [self init]) {
_resourcePath = [resourcePath retain];
_delegate = [delegate retain];
_params = [params retain];
}
[self loadFromObjectCache];
return self;
}
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params objectClass:(Class)klass delegate:(id)delegate {
if (self = [self init]) {
_resourcePath = [resourcePath retain];
_delegate = [delegate retain];
_params = [params retain];
_objectClass = [klass retain];
}
[self loadFromObjectCache];
return self;
}
- (id)initWithResourcePath:(NSString*)resourcePath params:(NSDictionary*)params objectClass:(Class)klass keyPath:(NSString*)keyPath delegate:(id)delegate {
if (self = [self init]) {
_resourcePath = [resourcePath retain];
_delegate = [delegate retain];
_params = [params retain];
_objectClass = [klass retain];
_keyPath = [keyPath retain];
}
[self loadFromObjectCache];
return self;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// NSObject
- (id)init {
if (self = [super init]) {
_method = RKRequestMethodGET;
_refreshRate = NSTimeIntervalSince1970; // Essentially, default to never
}
return self;
}
- (void)dealloc {
[_delegate release];
[_objectLoader.request cancel];
[_objectLoader release];
[_params release];
[_objects release];
[_objectClass release];
[_keyPath release];
[super dealloc];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// RKRequestDelegate
- (void)requestDidFinishLoad:(RKRequest*)request {
[self saveLoadedTime];
if ([_delegate respondsToSelector:@selector(rkModelDidFinishLoad)]) {
[_delegate rkModelDidFinishLoad];
}
}
//// TODO: I get replaced...
- (void)request:(RKRequest*)request didFailLoadWithError:(NSError*)error {
if ([_delegate respondsToSelector:@selector(rkModelDidFailLoadWithError:)]) {
[_delegate rkModelDidFailLoadWithError:error];
}
}
- (void)requestDidCancelLoad:(RKRequest*)request {
if ([_delegate respondsToSelector:@selector(rkModelDidCancelLoad)]) {
[_delegate rkModelDidCancelLoad];
}
}
- (BOOL)needsRefresh {
NSDate* loadedTime = self.loadedTime;
BOOL outdated = NO;
if (loadedTime) {
outdated = -[loadedTime timeIntervalSinceNow] > _refreshRate;
} else {
[self saveLoadedTime];
}
return outdated;
}
- (void)clearLoadedTime {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:_resourcePath];
}
- (void)saveLoadedTime {
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:_resourcePath];
}
- (NSDate*)loadedTime {
return [[NSUserDefaults standardUserDefaults] objectForKey:_resourcePath];
}
- (void)loadFromObjectCache {
RKManagedObjectStore* store = [RKObjectManager globalManager].objectStore;
NSArray* cachedObjects = nil;
if (store.managedObjectCache) {
cachedObjects = [RKManagedObject objectsWithFetchRequests:[store.managedObjectCache fetchRequestsForResourcePath:self.resourcePath]];
if (cachedObjects && [cachedObjects count] > 0) {
if ([_delegate respondsToSelector:@selector(rkModelDidStartLoad)]) {
[_delegate rkModelDidStartLoad];
}
_objects = [cachedObjects retain];
_loaded = YES;
if ([_delegate respondsToSelector:@selector(rkModelDidLoad)]) {
[_delegate rkModelDidLoad];
}
} else {
[self load];
}
}
if ([self needsRefresh]) {
[self load];
}
}
- (BOOL)errorWarrantsOptionToGoOffline:(NSError*)error {
switch ([error code]) {
case NSURLErrorTimedOut:
case NSURLErrorCannotFindHost:
case NSURLErrorCannotConnectToHost:
case NSURLErrorNetworkConnectionLost:
case NSURLErrorDNSLookupFailed:
case NSURLErrorNotConnectedToInternet:
case NSURLErrorInternationalRoamingOff:
return YES;
break;
default:
return NO;
break;
}
}
- (void)showAlertWithOptionToGoOfflineForError:(NSError*)error {
UIAlertView* alert = [[[UIAlertView alloc] initWithTitle:TTLocalizedString(@"Network Error", @"")
message:[error localizedDescription]
delegate:self
cancelButtonTitle:TTLocalizedString(@"OK", @"")
otherButtonTitles:TTLocalizedString(@"Go Offline", @""), nil] autorelease];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
// Go Offline button
if (1 == buttonIndex) {
[[RKObjectManager globalManager] goOffline];
}
}
- (void)modelsDidLoad:(NSArray*)models {
[models retain];
[_objects release];
_objects = models;
_loaded = YES;
// NOTE: You must finish load after clearing the loadingRequest and setting the loaded flag
if ([_delegate respondsToSelector:@selector(rkModelDidLoad)]) {
[_delegate rkModelDidLoad];
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// RKModelLoaderDelegate
// This callback is invoked after the request has been fully serviced. Finish the load here.
- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects {
[objectLoader release];
_objectLoader = nil;
[self modelsDidLoad:objects];
}
- (void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError *)error {
[objectLoader release];
_objectLoader = nil;
if ([self errorWarrantsOptionToGoOffline:error]) {
[self showAlertWithOptionToGoOfflineForError:error];
} else {
[_delegate didFailLoadWithError:error];
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// public
- (void)reset {
[self clearLoadedTime];
}
- (void)load {
if ([_delegate respondsToSelector:@selector(rkModelDidStartLoad)]) {
[_delegate rkModelDidStartLoad];
}
_objectLoader = [[[RKObjectManager globalManager] objectLoaderWithResourcePath:_resourcePath delegate:self] retain];
_objectLoader.method = _method;
_objectLoader.objectClass = _objectClass;
_objectLoader.keyPath = _keyPath;
_objectLoader.params = _params;
[_objectLoader send];
}
@end