From 06a387e4b2d778791c5b6725413653aae9fb096b Mon Sep 17 00:00:00 2001 From: Evadne Wu Date: Wed, 23 May 2012 17:29:07 +0800 Subject: [PATCH 01/32] fixes issues with nil path extension crashing applications --- IRRemoteResourceDownloadOperation.m | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/IRRemoteResourceDownloadOperation.m b/IRRemoteResourceDownloadOperation.m index 442a1da..4cccdf4 100644 --- a/IRRemoteResourceDownloadOperation.m +++ b/IRRemoteResourceDownloadOperation.m @@ -250,15 +250,20 @@ - (void) connectionDidFinishLoading:(NSURLConnection *)connection { NSString *utiType = [(NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (CFStringRef)self.mimeType, NULL) autorelease]; NSString *pathExtension = [(NSString *)UTTypeCopyPreferredTagWithClass((CFStringRef)utiType, kUTTagClassFilenameExtension) autorelease]; - NSString *fromPath = self.path; - NSString *toPath = [[self.path stringByDeletingPathExtension] stringByAppendingPathExtension:pathExtension]; - NSError *error = nil; - BOOL didMove = [fm moveItemAtPath:fromPath toPath:toPath error:&error]; - if (!didMove) { - NSLog(@"%s: %@ -> %@ Error: %@", __PRETTY_FUNCTION__, fromPath, toPath, error); - } else { - self.path = toPath; + if (pathExtension) { + + NSString *fromPath = self.path; + NSString *toPath = [[self.path stringByDeletingPathExtension] stringByAppendingPathExtension:pathExtension]; + NSError *error = nil; + + BOOL didMove = [fm moveItemAtPath:fromPath toPath:toPath error:&error]; + if (!didMove) { + NSLog(@"%s: %@ -> %@ Error: %@", __PRETTY_FUNCTION__, fromPath, toPath, error); + } else { + self.path = toPath; + } + } } From 6319a493a9b9d211864f13ff25bcac280a08e12d Mon Sep 17 00:00:00 2001 From: Evadne Wu Date: Fri, 25 May 2012 21:40:12 +0800 Subject: [PATCH 02/32] nils the file handle aggressively --- IRRemoteResourceDownloadOperation.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/IRRemoteResourceDownloadOperation.m b/IRRemoteResourceDownloadOperation.m index 4cccdf4..870781b 100644 --- a/IRRemoteResourceDownloadOperation.m +++ b/IRRemoteResourceDownloadOperation.m @@ -165,6 +165,7 @@ - (void) cancel { [self onOriginalQueue: ^ { [self.fileHandle closeFile]; + self.fileHandle = nil; }]; if (self.executing) { @@ -241,6 +242,7 @@ - (void) connectionDidFinishLoading:(NSURLConnection *)connection { [self onOriginalQueue: ^ { [self.fileHandle closeFile]; + self.fileHandle = nil; if (self.mimeType) { @@ -285,6 +287,7 @@ - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)er [self onOriginalQueue: ^ { [self.fileHandle closeFile]; + self.fileHandle = nil; [[NSFileManager defaultManager] removeItemAtPath:self.path error:nil]; From 2060de9f68da37a98c3fca7e48c6369489902fde Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Wed, 13 Jun 2012 18:22:56 +0800 Subject: [PATCH 03/32] add log to all API requests --- IRWebAPIEngine.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/IRWebAPIEngine.m b/IRWebAPIEngine.m index 4c68921..bcb6170 100644 --- a/IRWebAPIEngine.m +++ b/IRWebAPIEngine.m @@ -251,6 +251,8 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in }; NSDictionary *finalizedContext = [self requestContextByTransformingContext:[self baseRequestContextWithMethodName:inMethodName arguments:inArgumentsOrNil options:inOptionsOrNil] forMethodNamed:inMethodName]; + + NSLog(@"Send: %@", [finalizedContext objectForKey:@"kIRWebAPIEngineRequestHTTPBaseURL"]); NSURLRequest *request = [self requestWithContext:finalizedContext]; @@ -262,6 +264,8 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in [self setInternalSuccessHandler: ^ (NSData *inResponse) { + NSLog(@"Success: %@", [finalizedContext objectForKey:@"kIRWebAPIEngineRequestHTTPBaseURL"]); + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; BOOL shouldRetry = NO, notifyDelegate = NO; @@ -294,6 +298,8 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in [self setInternalFailureHandler: ^ { + NSLog(@"Fail: %@", [finalizedContext objectForKey:@"kIRWebAPIEngineRequestHTTPBaseURL"]); + BOOL shouldRetry = NO, notifyDelegate = NO; NSMutableDictionary *responseContext = [self internalResponseContextForConnection:connection]; NSDictionary *transformedResopnse = [self responseByTransformingResponse:[NSDictionary dictionary] withRequestContext:responseContext forMethodNamed:inMethodName]; From d5cd4a95ade9129a676bd1290702e05882755c7f Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Thu, 14 Jun 2012 16:44:51 +0800 Subject: [PATCH 04/32] fix logging --- IRWebAPIEngine.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IRWebAPIEngine.m b/IRWebAPIEngine.m index bcb6170..c4a7747 100644 --- a/IRWebAPIEngine.m +++ b/IRWebAPIEngine.m @@ -252,8 +252,6 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in NSDictionary *finalizedContext = [self requestContextByTransformingContext:[self baseRequestContextWithMethodName:inMethodName arguments:inArgumentsOrNil options:inOptionsOrNil] forMethodNamed:inMethodName]; - NSLog(@"Send: %@", [finalizedContext objectForKey:@"kIRWebAPIEngineRequestHTTPBaseURL"]); - NSURLRequest *request = [self requestWithContext:finalizedContext]; void (^returnedBlock) (void) = ^ { @@ -322,6 +320,8 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in nil] forConnection:connection]; + NSLog(@"Send: %@", [finalizedContext objectForKey:@"kIRWebAPIEngineRequestHTTPBaseURL"]); + [connection start]; }); From 89a2ac7570586638b88b998b8e143f6a7c4e0ab3 Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Tue, 19 Jun 2012 11:52:14 +0800 Subject: [PATCH 05/32] log full URL --- IRRemoteResourceDownloadOperation.m | 6 ++++++ IRWebAPIEngine.m | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/IRRemoteResourceDownloadOperation.m b/IRRemoteResourceDownloadOperation.m index 870781b..5b28ae3 100644 --- a/IRRemoteResourceDownloadOperation.m +++ b/IRRemoteResourceDownloadOperation.m @@ -151,6 +151,8 @@ - (void) main { // Do not mutate the URL // self.url = usedRequest.URL; + NSLog(@"Send: %@", usedRequest.URL); + [self.connection start]; }]; @@ -236,6 +238,8 @@ - (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data - (void) connectionDidFinishLoading:(NSURLConnection *)connection { + NSLog(@"Success: %@", [self underlyingRequest].URL); + if ([self isCancelled]) return; @@ -281,6 +285,8 @@ - (void) connectionDidFinishLoading:(NSURLConnection *)connection { - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { + NSLog(@"Fail: %@", [self underlyingRequest].URL); + if ([self isCancelled]) return; diff --git a/IRWebAPIEngine.m b/IRWebAPIEngine.m index c4a7747..760267b 100644 --- a/IRWebAPIEngine.m +++ b/IRWebAPIEngine.m @@ -262,7 +262,7 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in [self setInternalSuccessHandler: ^ (NSData *inResponse) { - NSLog(@"Success: %@", [finalizedContext objectForKey:@"kIRWebAPIEngineRequestHTTPBaseURL"]); + NSLog(@"Success: %@", request.URL); NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; @@ -296,7 +296,7 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in [self setInternalFailureHandler: ^ { - NSLog(@"Fail: %@", [finalizedContext objectForKey:@"kIRWebAPIEngineRequestHTTPBaseURL"]); + NSLog(@"Fail: %@", request.URL); BOOL shouldRetry = NO, notifyDelegate = NO; NSMutableDictionary *responseContext = [self internalResponseContextForConnection:connection]; @@ -320,7 +320,7 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in nil] forConnection:connection]; - NSLog(@"Send: %@", [finalizedContext objectForKey:@"kIRWebAPIEngineRequestHTTPBaseURL"]); + NSLog(@"Send: %@", request.URL); [connection start]; From 849beee2a8710a987394cbabba8db89f8099851f Mon Sep 17 00:00:00 2001 From: Evadne Wu Date: Fri, 22 Jun 2012 11:15:48 +0800 Subject: [PATCH 06/32] decrufting --- IRRemoteResourceDownloadOperation.m | 6 -- IRWebAPIEngine+FormMultipart.h | 100 ---------------------------- IRWebAPIEngine.m | 16 +---- 3 files changed, 2 insertions(+), 120 deletions(-) diff --git a/IRRemoteResourceDownloadOperation.m b/IRRemoteResourceDownloadOperation.m index 5b28ae3..870781b 100644 --- a/IRRemoteResourceDownloadOperation.m +++ b/IRRemoteResourceDownloadOperation.m @@ -151,8 +151,6 @@ - (void) main { // Do not mutate the URL // self.url = usedRequest.URL; - NSLog(@"Send: %@", usedRequest.URL); - [self.connection start]; }]; @@ -238,8 +236,6 @@ - (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data - (void) connectionDidFinishLoading:(NSURLConnection *)connection { - NSLog(@"Success: %@", [self underlyingRequest].URL); - if ([self isCancelled]) return; @@ -285,8 +281,6 @@ - (void) connectionDidFinishLoading:(NSURLConnection *)connection { - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { - NSLog(@"Fail: %@", [self underlyingRequest].URL); - if ([self isCancelled]) return; diff --git a/IRWebAPIEngine+FormMultipart.h b/IRWebAPIEngine+FormMultipart.h index 401cad5..9aead71 100644 --- a/IRWebAPIEngine+FormMultipart.h +++ b/IRWebAPIEngine+FormMultipart.h @@ -16,103 +16,3 @@ extern NSString * const kIRWebAPIEngineRequestContextFormMultipartFieldsKey; + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer; @end - - - - - -/* - - +defaultFormMultipartTransformer emits a block that expects : - - { - - kIRWebAPIEngineRequestContextFormMultipartFieldsKey = { - - aFormName = "aStringValue", - - anotherFormName = file://myFile.txt , - - anotherThing = <00325296> - - } - - } - - Where a string value gets sent, a URL gets mapped and dumped, its UTI guessed, and a NSData simply copied. - - The HTTP method is changed to POST and there must be nothing in the old HTTP body. - - - Since transforming could be expensive you explicitly hook the transformer up. - This category works with the +defaultCleanUpTemporaryFilesResponseTransformer so as to keep things neat. - - Here’s a use case: - - - (void) testMultipart { - - NSString *path = [[IRWebAPIEngine newTemporaryFileURL] path]; - - [[NSData dataWithData:UIImagePNGRepresentation(( ^ { - - UIGraphicsBeginImageContext([UIScreen mainScreen].bounds.size); - CGContextRef context = UIGraphicsGetCurrentContext(); - - CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor); - CGContextFillRect(context, [UIScreen mainScreen].bounds); - - [self.window.layer renderInContext:ctx]; - - UIImage *returnedImage = UIGraphicsGetImageFromCurrentImageContext(); - - UIGraphicsEndImageContext(); - - - return returnedImage; - - })())] writeToFile:path atomically:YES]; - - - IRWebAPIEngine *testEngine = [[[IRWebAPIEngine alloc] initWithContext:(( ^ { - - IRWebAPIContext *returnedContext = [[[IRWebAPIContext alloc] initWithBaseURL:[NSURL URLWithString:@"http://Museo.local/~evadne/postTest/"]] autorelease]; - - return returnedContext; - - })())] autorelease]; - - [testEngine.globalRequestPreTransformers addObject:[[testEngine class] defaultFormMultipartTransformer]]; - [testEngine.globalResponsePostTransformers addObject:[[testEngine class] defaultCleanUpTemporaryFilesResponseTransformer]]; - - [testEngine fireAPIRequestNamed:@"test.php" withArguments:nil options:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSDictionary dictionaryWithObjectsAndKeys: - - [NSURL fileURLWithPath:path], @"image", - - nil], kIRWebAPIEngineRequestContextFormMultipartFieldsKey, - - nil] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - NSLog(@"Success: %@", inResponseOrNil); - - } failureHandler:nil]; - - } - - - This PHP snippet works with OS X 10.6’s bundled Apache: - - - -*/ - - - - diff --git a/IRWebAPIEngine.m b/IRWebAPIEngine.m index 760267b..c11b0e8 100644 --- a/IRWebAPIEngine.m +++ b/IRWebAPIEngine.m @@ -141,10 +141,8 @@ - (void) dealloc { - (void) ensureResponseParserExistence { - if (self.parser) return; - - NSLog(@"Warning: IRWebAPIEngine is designed to work with a parser. Without one, the response will be sent as a default dictionary."); - self.parser = IRWebAPIResponseDefaultParserMake(); + if (!self.parser) + self.parser = IRWebAPIResponseDefaultParserMake(); } @@ -177,8 +175,6 @@ - (void) handleUnparsableResponseForData:(NSData *)inData context:(NSDictionary NSMutableDictionary *displayedContext = [inContext mutableCopy]; [displayedContext setObject:@"< REMOVED> " forKey:kIRWebAPIEngineRequestHTTPBody]; - NSLog(@"Context: %@", displayedContext); - // This can potentially clog up the wirings // IRWebAPIResponseParser defaultParser = IRWebAPIResponseDefaultParserMake(); // NSDictionary *debugOutput = defaultParser(inData); @@ -262,8 +258,6 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in [self setInternalSuccessHandler: ^ (NSData *inResponse) { - NSLog(@"Success: %@", request.URL); - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; BOOL shouldRetry = NO, notifyDelegate = NO; @@ -296,8 +290,6 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in [self setInternalFailureHandler: ^ { - NSLog(@"Fail: %@", request.URL); - BOOL shouldRetry = NO, notifyDelegate = NO; NSMutableDictionary *responseContext = [self internalResponseContextForConnection:connection]; NSDictionary *transformedResopnse = [self responseByTransformingResponse:[NSDictionary dictionary] withRequestContext:responseContext forMethodNamed:inMethodName]; @@ -320,8 +312,6 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in nil] forConnection:connection]; - NSLog(@"Send: %@", request.URL); - [connection start]; }); @@ -370,8 +360,6 @@ - (void) connectionDidFinishLoading:(NSURLConnection *)inConnection { } @catch (NSException *e) { - NSLog(@"Handle Exception: %@ %@", e, inConnection); - [self internalFailureHandlerForConnection:inConnection](); } From 4415beec613ff9cb2c37697f7b8a68a4ba117157 Mon Sep 17 00:00:00 2001 From: Evadne Wu Date: Fri, 22 Jun 2012 14:38:29 +0800 Subject: [PATCH 07/32] WIP for code modernization - uses Automatic Reference Counting - fixes several issues - removes Cappuccino variant - removes Twitter / Google Reader / TwitPic interfaces - fixes several other semantic issues --- IRRemoteResourceDownloadOperation.m | 61 ++- IRRemoteResourcesManager.m | 61 ++- IRSiteReachability.j | 33 -- IRWebAPIAuthenticator.m | 13 - IRWebAPIContext.j | 78 ---- IRWebAPICredentials.m | 37 +- IRWebAPIEngine+FormMultipart.m | 8 +- IRWebAPIEngine+FormURLEncoding.m | 6 +- IRWebAPIEngine+LocalCaching.m | 7 +- IRWebAPIEngine.h | 4 +- IRWebAPIEngine.j | 436 ------------------- IRWebAPIEngine.m | 97 ++--- IRWebAPIContext.h => IRWebAPIEngineContext.h | 18 +- IRWebAPIContext.m => IRWebAPIEngineContext.m | 24 +- IRWebAPIGoogleReaderAuthenticator.h | 18 - IRWebAPIGoogleReaderAuthenticator.m | 106 ----- IRWebAPIGoogleReaderInterface.h | 35 -- IRWebAPIGoogleReaderInterface.m | 220 ---------- IRWebAPIHelpers.h | 2 - IRWebAPIHelpers.m | 99 +---- IRWebAPIInterface+Validators.m | 29 +- IRWebAPIInterface.h | 2 +- IRWebAPIInterface.m | 26 +- IRWebAPIKit.h | 24 +- IRWebAPIKit.j | 34 -- IRWebAPIKit.xcodeproj/project.pbxproj | 210 ++------- IRWebAPIKitDefines.h | 22 +- IRWebAPIMockJSONPConnection.j | 115 ----- IRWebAPIModel.j | 87 ---- IRWebAPIOperation.h | 13 + IRWebAPIOperation.m | 13 + IRWebAPIResponseParser.m | 234 +++------- IRWebAPITwitPicInterface.h | 16 - IRWebAPITwitPicInterface.m | 154 ------- IRWebAPITwitterInterface+DirectMessages.h | 25 -- IRWebAPITwitterInterface+DirectMessages.m | 123 ------ IRWebAPITwitterInterface+Friendships.h | 44 -- IRWebAPITwitterInterface+Friendships.m | 144 ------ IRWebAPITwitterInterface+Geo.h | 16 - IRWebAPITwitterInterface+Geo.m | 72 --- IRWebAPITwitterInterface+Lists.h | 53 --- IRWebAPITwitterInterface+Lists.m | 251 ----------- IRWebAPITwitterInterface+Timeline.h | 56 --- IRWebAPITwitterInterface+Timeline.m | 231 ---------- IRWebAPITwitterInterface+User.h | 18 - IRWebAPITwitterInterface+User.m | 43 -- IRWebAPITwitterInterface+Validators.h | 36 -- IRWebAPITwitterInterface+Validators.m | 125 ------ IRWebAPITwitterInterface.h | 90 ---- IRWebAPITwitterInterface.m | 173 -------- IRWebAPIXOAuthAuthenticator.m | 44 +- 51 files changed, 279 insertions(+), 3607 deletions(-) delete mode 100644 IRSiteReachability.j delete mode 100644 IRWebAPIContext.j delete mode 100644 IRWebAPIEngine.j rename IRWebAPIContext.h => IRWebAPIEngineContext.h (57%) rename IRWebAPIContext.m => IRWebAPIEngineContext.m (53%) delete mode 100644 IRWebAPIGoogleReaderAuthenticator.h delete mode 100644 IRWebAPIGoogleReaderAuthenticator.m delete mode 100644 IRWebAPIGoogleReaderInterface.h delete mode 100644 IRWebAPIGoogleReaderInterface.m delete mode 100644 IRWebAPIKit.j delete mode 100644 IRWebAPIMockJSONPConnection.j delete mode 100644 IRWebAPIModel.j create mode 100644 IRWebAPIOperation.h create mode 100644 IRWebAPIOperation.m delete mode 100644 IRWebAPITwitPicInterface.h delete mode 100644 IRWebAPITwitPicInterface.m delete mode 100644 IRWebAPITwitterInterface+DirectMessages.h delete mode 100644 IRWebAPITwitterInterface+DirectMessages.m delete mode 100644 IRWebAPITwitterInterface+Friendships.h delete mode 100644 IRWebAPITwitterInterface+Friendships.m delete mode 100644 IRWebAPITwitterInterface+Geo.h delete mode 100644 IRWebAPITwitterInterface+Geo.m delete mode 100644 IRWebAPITwitterInterface+Lists.h delete mode 100644 IRWebAPITwitterInterface+Lists.m delete mode 100644 IRWebAPITwitterInterface+Timeline.h delete mode 100644 IRWebAPITwitterInterface+Timeline.m delete mode 100644 IRWebAPITwitterInterface+User.h delete mode 100644 IRWebAPITwitterInterface+User.m delete mode 100644 IRWebAPITwitterInterface+Validators.h delete mode 100644 IRWebAPITwitterInterface+Validators.m delete mode 100644 IRWebAPITwitterInterface.h delete mode 100644 IRWebAPITwitterInterface.m diff --git a/IRRemoteResourceDownloadOperation.m b/IRRemoteResourceDownloadOperation.m index 870781b..b9cc624 100644 --- a/IRRemoteResourceDownloadOperation.m +++ b/IRRemoteResourceDownloadOperation.m @@ -41,7 +41,8 @@ - (void) onOriginalQueue:(void(^)(void))aBlock; @implementation IRRemoteResourceDownloadOperation @synthesize path, mimeType, url, processedBytes, totalBytes, preferredByteOffset, executing, finished, cancelled; -@synthesize fileHandle, connection; +@synthesize fileHandle = _fileHandle; +@synthesize connection = _connection; @synthesize actualDispatchQueue; @synthesize onMain; @synthesize appendedCompletionBlocks; @@ -52,34 +53,21 @@ + (IRRemoteResourceDownloadOperation *) operationWithURL:(NSURL *)aRemoteURL pat NSParameterAssert(aRemoteURL); NSParameterAssert(aLocalPath); - IRRemoteResourceDownloadOperation *returnedOperation = [[[self alloc] init] autorelease]; + IRRemoteResourceDownloadOperation *returnedOperation = [[self alloc] init]; returnedOperation.url = aRemoteURL; returnedOperation.path = aLocalPath; returnedOperation.onMain = aPrelude; returnedOperation.completionBlock = aBlock; + return returnedOperation; } - (void) dealloc { - [mimeType release]; - - [path release]; - [url release]; - [fileHandle release]; - - __block NSURLConnection *nrConnection = connection; - dispatch_async(dispatch_get_main_queue(), ^ { - [nrConnection release]; - }); - - [onMain release]; - [appendedCompletionBlocks release]; + [_connection cancel]; - [super dealloc]; - } - (void) onMainQueue:(void(^)(void))aBlock { @@ -135,18 +123,19 @@ - (void) main { [self onMainQueue: ^ { - NSMutableURLRequest *usedRequest = [NSMutableURLRequest requestWithURL:self.url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10]; - NSURLConnection *usedConnection = [[[NSURLConnection alloc] initWithRequest:usedRequest delegate:self startImmediately:NO] autorelease]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10]; + + NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; - objc_setAssociatedObject(usedConnection, &kIRRemoteResourcesDownloadOperation_connectionRequest, usedRequest, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - self.connection = usedConnection; + objc_setAssociatedObject(connection, &kIRRemoteResourcesDownloadOperation_connectionRequest, request, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + self.connection = connection; [self.delegate remoteResourceDownloadOperationWillBegin:self]; - usedConnection = [[[NSURLConnection alloc] initWithRequest:usedRequest delegate:self startImmediately:NO] autorelease]; + connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; - objc_setAssociatedObject(usedConnection, &kIRRemoteResourcesDownloadOperation_connectionRequest, usedRequest, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - self.connection = usedConnection; + objc_setAssociatedObject(connection, &kIRRemoteResourcesDownloadOperation_connectionRequest, request, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + self.connection = connection; // Do not mutate the URL // self.url = usedRequest.URL; @@ -248,13 +237,16 @@ - (void) connectionDidFinishLoading:(NSURLConnection *)connection { // If there is a MIME type available, rename the underlying file - NSFileManager *fm = [NSFileManager defaultManager]; + CFStringRef const tag = (__bridge CFStringRef)self.mimeType; + NSString *utiType = (NSString *)CFBridgingRelease(UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, tag, NULL)); - NSString *utiType = [(NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (CFStringRef)self.mimeType, NULL) autorelease]; - NSString *pathExtension = [(NSString *)UTTypeCopyPreferredTagWithClass((CFStringRef)utiType, kUTTagClassFilenameExtension) autorelease]; + CFStringRef const tagClass = kUTTagClassFilenameExtension; + NSString *pathExtension = (NSString *)CFBridgingRelease(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)utiType, tagClass)); if (pathExtension) { + NSFileManager * const fm = [NSFileManager defaultManager]; + NSString *fromPath = self.path; NSString *toPath = [[self.path stringByDeletingPathExtension] stringByAppendingPathExtension:pathExtension]; NSError *error = nil; @@ -305,8 +297,9 @@ - (NSURLRequest *) connection:(NSURLConnection *)connection willSendRequest:(NSU if (!aRedirectResponse) return aRequest; - NSMutableURLRequest *mutatedRequest = [[[self underlyingRequest] mutableCopy] autorelease]; + NSMutableURLRequest *mutatedRequest = [[self underlyingRequest] mutableCopy]; mutatedRequest.URL = [aRequest URL]; + return mutatedRequest; } @@ -382,17 +375,17 @@ - (NSString *) description { - (NSMutableArray *) appendedCompletionBlocks { - if (appendedCompletionBlocks) - return appendedCompletionBlocks; + if (!appendedCompletionBlocks) { + appendedCompletionBlocks = [NSMutableArray array]; + } - appendedCompletionBlocks = [[NSMutableArray array] retain]; return appendedCompletionBlocks; } - (void) appendCompletionBlock:(void (^)(void))aBlock { - [self.appendedCompletionBlocks addObject:[[aBlock copy] autorelease]]; + [self.appendedCompletionBlocks addObject:[aBlock copy]]; } @@ -400,7 +393,7 @@ - (void) invokeCompletionBlocks { @synchronized (self) { - for (void(^aBlock)(void) in [[self.appendedCompletionBlocks copy] autorelease]) + for (void(^aBlock)(void) in self.appendedCompletionBlocks) aBlock(); self.appendedCompletionBlocks = [NSMutableArray array]; @@ -414,7 +407,7 @@ - (IRRemoteResourceDownloadOperation *) continuationOperationCancellingCurrentOp if (!self.path || !self.url) return nil; - __block IRRemoteResourceDownloadOperation *continuationOperation = [[[[self class] alloc] init] autorelease]; + __block IRRemoteResourceDownloadOperation *continuationOperation = [[[self class] alloc] init]; continuationOperation.path = self.path; continuationOperation.url = self.url; continuationOperation.preferredByteOffset = self.processedBytes; diff --git a/IRRemoteResourcesManager.m b/IRRemoteResourcesManager.m index 41c1003..3b0fa0b 100644 --- a/IRRemoteResourcesManager.m +++ b/IRRemoteResourcesManager.m @@ -81,9 +81,9 @@ - (id) init { queue = [[NSOperationQueue alloc] init]; queue.maxConcurrentOperationCount = 1; operationQueue = dispatch_queue_create("iridia.remoteResourcesManager.operationQueue", DISPATCH_QUEUE_SERIAL); - enqueuedOperations = [[NSMutableArray array] retain]; + enqueuedOperations = [NSMutableArray array]; - allOperations = [[NSMutableDictionary dictionary] retain]; + allOperations = [NSMutableDictionary dictionary]; allOperationsQueue = dispatch_queue_create("iridia.remoteResourcesManager.operationsManagingQueue", DISPATCH_QUEUE_SERIAL); return self; @@ -96,20 +96,10 @@ - (void) dealloc { if (operationQueue) dispatch_release(operationQueue); - - [queue release]; - [enqueuedOperations release]; - [cacheDirectoryPath release]; - - [onRemoteResourceDownloadOperationWillBegin release]; - - [allOperations release]; - + if (allOperationsQueue) dispatch_release(allOperationsQueue); - [super dealloc]; - } @@ -290,12 +280,12 @@ - (IRRemoteResourceDownloadOperation *) enqueuedOperationForURL:(NSURL *)anURL { - (IRRemoteResourceDownloadOperation *) prospectiveOperationForURL:(NSURL *)anURL enqueue:(BOOL)enqueuesOperation { - __block __typeof__(self) nrSelf = self; + __weak IRRemoteResourcesManager *wSelf = self; __block IRRemoteResourceDownloadOperation *operation = nil; operation = [IRRemoteResourceDownloadOperation operationWithURL:anURL path:[self pathForCachedContentsOfRemoteURL:anURL usedProspectiveURL:NULL] prelude: ^ { - [nrSelf.delegate remoteResourcesManager:nrSelf didBeginDownloadingResourceAtURL:operation.url]; + [wSelf.delegate remoteResourcesManager:wSelf didBeginDownloadingResourceAtURL:operation.url]; } completion: ^ { @@ -305,15 +295,13 @@ - (IRRemoteResourceDownloadOperation *) prospectiveOperationForURL:(NSURL *)anUR if (didFinish) { - [operation retain]; - dispatch_async(dispatch_get_main_queue(), ^ { [operation invokeCompletionBlocks]; - [operation autorelease]; + operation = nil; - [nrSelf notifyUpdatedResourceForRemoteURL:operationURL]; - [nrSelf.delegate remoteResourcesManager:nrSelf didFinishDownloadingResourceAtURL:operationURL]; + [wSelf notifyUpdatedResourceForRemoteURL:operationURL]; + [wSelf.delegate remoteResourcesManager:wSelf didFinishDownloadingResourceAtURL:operationURL]; }); @@ -321,23 +309,25 @@ - (IRRemoteResourceDownloadOperation *) prospectiveOperationForURL:(NSURL *)anUR dispatch_async(dispatch_get_main_queue(), ^ { - [nrSelf.delegate remoteResourcesManager:nrSelf didFailDownloadingResourceAtURL:operationURL]; + [wSelf.delegate remoteResourcesManager:wSelf didFailDownloadingResourceAtURL:operationURL]; + operation = nil; + }); } dispatch_async(dispatch_get_main_queue(), ^{ - [nrSelf beginSuspendingOperationQueue]; + [wSelf beginSuspendingOperationQueue]; - [nrSelf performInBackground: ^ { + [wSelf performInBackground: ^ { - [nrSelf enqueueOperationsIfNeeded]; + [wSelf enqueueOperationsIfNeeded]; dispatch_async(dispatch_get_main_queue(), ^{ - [nrSelf endSuspendingOperationQueue]; + [wSelf endSuspendingOperationQueue]; }); @@ -461,7 +451,6 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri // Hoist it — This is last come, first serve - [[operation retain] autorelease]; [self.enqueuedOperations removeObject:operation]; [self.enqueuedOperations insertObject:operation atIndex:0]; @@ -545,18 +534,20 @@ - (void) enqueueOperationsIfNeeded { - (NSString *) cacheDirectoryPath { - if (cacheDirectoryPath) - return cacheDirectoryPath; + if (!cacheDirectoryPath) { + + NSString *prospectivePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:NSStringFromClass([self class])]; - NSString *prospectivePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:NSStringFromClass([self class])]; + NSError *cacheDirectoryCreationError; + if (![[NSFileManager defaultManager] createDirectoryAtPath:prospectivePath withIntermediateDirectories:YES attributes:nil error:&cacheDirectoryCreationError]) { + NSLog(@"Error occurred while creating or assuring cache directory: %@", cacheDirectoryCreationError); + return nil; + } + + cacheDirectoryPath = [prospectivePath copy]; - NSError *cacheDirectoryCreationError; - if (![[NSFileManager defaultManager] createDirectoryAtPath:prospectivePath withIntermediateDirectories:YES attributes:nil error:&cacheDirectoryCreationError]) { - NSLog(@"Error occurred while creating or assuring cache directory: %@", cacheDirectoryCreationError); - return nil; } - cacheDirectoryPath = [prospectivePath retain]; return cacheDirectoryPath; } @@ -580,7 +571,7 @@ - (BOOL) clearCacheDirectory { - (void) notifyUpdatedResourceForRemoteURL:(NSURL *)inRemoteURL { - inRemoteURL = [[inRemoteURL copy] autorelease]; + inRemoteURL = [inRemoteURL copy]; dispatch_async(dispatch_get_main_queue(), ^ { diff --git a/IRSiteReachability.j b/IRSiteReachability.j deleted file mode 100644 index a7163c6..0000000 --- a/IRSiteReachability.j +++ /dev/null @@ -1,33 +0,0 @@ -// IRSiteReachability.j -// Evadne Wu at Iridia, 2010 - - - - - -var _IRSiteReachabilityResult = nil; - -var kIRSiteReachabilityResultUnknown = @"IRSiteReachabilityResultUnknown", - kIRSiteReachabilityResultReachable = @"IRSiteReachabilityResultReachable", - kIRSiteReachabilityResultUnavailable = @"IRSiteReachabilityResultUnavailable"; - - - - - - - - - - -@implementation IRSiteReachability : CPObject { - -} - -+ (IRSiteReachabilityType) status { - - return _IRSiteReachabilityResult; - -} - -@end \ No newline at end of file diff --git a/IRWebAPIAuthenticator.m b/IRWebAPIAuthenticator.m index f6f69ab..26199c0 100644 --- a/IRWebAPIAuthenticator.m +++ b/IRWebAPIAuthenticator.m @@ -38,19 +38,6 @@ - (void) createTransformerBlocks { } -- (void) dealloc { - - self.globalRequestPreTransformerBlock = nil; - self.globalRequestPostTransformerBlock = nil; - self.globalResponsePreTransformerBlock = nil; - self.globalResponsePostTransformerBlock = nil; - - self.currentCredentials = nil; - - [super dealloc]; - -} - - (void) associateWithEngine:(IRWebAPIEngine *)inEngine { if (self.globalRequestPreTransformerBlock) diff --git a/IRWebAPIContext.j b/IRWebAPIContext.j deleted file mode 100644 index ba5e475..0000000 --- a/IRWebAPIContext.j +++ /dev/null @@ -1,78 +0,0 @@ -// IRWebAPIContext.j -// Evadne Wu at Iridia, 2010 - - - - - -@class IRWebAPIEngine; - - - - - -@implementation IRWebAPIContext : CPObject { - - CPURL baseURL @accessors; - -} - -+ (IRWebAPIContext) contextWithBaseURL:(CPURL)inURL { - - return [[[self class] alloc] initWithBaseURL:inURL]; - -} - - - - - -- (IRWebAPIContext) initWithBaseURL:(CPURL)inURL { - - self = [super init]; if (self == nil) return nil; - - [self setBaseURL:inURL]; - - return self; - -} - - - - - -- (CPURL) connectionURLForMethodNamed:(CPString)methodName additions:(CPString)additions { - - var baseURLString = String([[self baseURL] absoluteString]); - baseURLString = baseURLString.replace("#{methodName}", (methodName || "")); - baseURLString = baseURLString.replace("#{methodArguments}", (additions || "")); - - return [CPURL URLWithString:baseURLString]; - -} - -- (CPURL) connectionURLForPOSTMethodNamed:(CPString)methodName { - - var baseURLString = String([[self baseURL] absoluteString]); - baseURLString = baseURLString.replace("#{methodName}", (methodName || "")); - baseURLString = baseURLString.replace("#{methodArguments}", ""); - baseURLString = baseURLString.replace("?", ""); - - return [CPURL URLWithString:baseURLString]; - -} - - - - -- (CPString) description { - - return [super description] + @" — " + [baseURL description]; - -} - -@end - - - - diff --git a/IRWebAPICredentials.m b/IRWebAPICredentials.m index 1327602..c57c431 100644 --- a/IRWebAPICredentials.m +++ b/IRWebAPICredentials.m @@ -46,24 +46,6 @@ - (id) initWithIdentifier:(NSString *)inIdentifier qualifier:(NSString *)inQuali } -- (void) dealloc { - - self.identifier = nil; - self.identifierPlaceholder = nil; - self.identifierLabelText = nil; - - self.qualifier = nil; - self.qualifierPlaceholder = nil; - self.qualifierLabelText = nil; - - self.displayName = nil; - self.notes = nil; - self.userInfo = nil; - - [super dealloc]; - -} - - (id) initWithCoder:(NSCoder *)inCoder { self = [self init]; if (!self) return nil; @@ -98,27 +80,10 @@ - (void) encodeWithCoder:(NSCoder *)inCoder { } -- (id)copyWithZone:(NSZone *)zone { +- (id) copyWithZone:(NSZone *)zone { return self; -// Although copying sounds good, it breaks our hash in an authentication manager - - IRWebAPICredentials *copy = [[[self class] allocWithZone: zone] init]; - - copy.identifier = self.identifier; - copy.identifierPlaceholder = self.identifierPlaceholder; - copy.identifierLabelText = self.identifierLabelText; - copy.qualifier = self.qualifier; - copy.qualifierPlaceholder = self.qualifierPlaceholder; - copy.qualifierLabelText = self.qualifierLabelText; - copy.displayName = self.displayName; - copy.notes = self.notes; - copy.userInfo = [[self.userInfo copy] autorelease]; - copy.authenticated = self.authenticated; - - return copy; - } - (NSString *) description { diff --git a/IRWebAPIEngine+FormMultipart.m b/IRWebAPIEngine+FormMultipart.m index 2244ed2..389ffeb 100644 --- a/IRWebAPIEngine+FormMultipart.m +++ b/IRWebAPIEngine+FormMultipart.m @@ -16,17 +16,17 @@ @implementation IRWebAPIEngine (FormMultipart) + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { - return [[(^ (NSDictionary *inOriginalContext) { + return [(^ (NSDictionary *inOriginalContext) { NSDictionary *formNamesToContents = [inOriginalContext objectForKey:kIRWebAPIEngineRequestContextFormMultipartFieldsKey]; if(!formNamesToContents || ([formNamesToContents count] == 0)) return inOriginalContext; - NSMutableDictionary *returnedContext = [[inOriginalContext mutableCopy] autorelease]; + NSMutableDictionary *returnedContext = [inOriginalContext mutableCopy]; NSError *error; - NSURL *fileHandleURL = [[[self class] newTemporaryFileURL] autorelease]; + NSURL *fileHandleURL = [[self class] newTemporaryFileURL]; if (![[NSFileManager defaultManager] createFileAtPath:[fileHandleURL path] contents:[NSData data] attributes:nil]) { @@ -167,7 +167,7 @@ + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { return (NSDictionary *)returnedContext; - }) copy] autorelease]; + }) copy]; } diff --git a/IRWebAPIEngine+FormURLEncoding.m b/IRWebAPIEngine+FormURLEncoding.m index 9c6b1db..804bba7 100644 --- a/IRWebAPIEngine+FormURLEncoding.m +++ b/IRWebAPIEngine+FormURLEncoding.m @@ -15,14 +15,14 @@ @implementation IRWebAPIEngine (FormURLEncoding) + (IRWebAPIRequestContextTransformer) defaultFormURLEncodingTransformer { - return [[(^ (NSDictionary *inOriginalContext) { + return [(^ (NSDictionary *inOriginalContext) { NSDictionary *formNamesToContents = [inOriginalContext objectForKey:kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey]; if (![formNamesToContents count]) return inOriginalContext; - NSMutableDictionary *returnedContext = [[inOriginalContext mutableCopy] autorelease]; + NSMutableDictionary *returnedContext = [inOriginalContext mutableCopy]; NSMutableDictionary *headerFields = [returnedContext objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields]; if (!headerFields) { @@ -43,7 +43,7 @@ + (IRWebAPIRequestContextTransformer) defaultFormURLEncodingTransformer { return (NSDictionary *)returnedContext; - }) copy] autorelease]; + }) copy]; } diff --git a/IRWebAPIEngine+LocalCaching.m b/IRWebAPIEngine+LocalCaching.m index cfc0e37..dbae292 100644 --- a/IRWebAPIEngine+LocalCaching.m +++ b/IRWebAPIEngine+LocalCaching.m @@ -34,8 +34,7 @@ + (NSURL *) newTemporaryFileURL { }; - NSURL *fileURL = [[NSURL fileURLWithPath:[preferredCacheDirectoryPath stringByAppendingPathComponent:IRWebAPIKitNonce()]] retain]; - return fileURL; + return [NSURL fileURLWithPath:[preferredCacheDirectoryPath stringByAppendingPathComponent:IRWebAPIKitNonce()]]; } @@ -62,7 +61,7 @@ + (BOOL) cleanUpTemporaryFileAtURL:(NSURL *)inTemporaryFileURL { + (IRWebAPIResponseContextTransformer) defaultCleanUpTemporaryFilesResponseTransformer { - return [[(^ (NSDictionary *inParsedResponse, NSDictionary *inResponseContext) { + return [(^ (NSDictionary *inParsedResponse, NSDictionary *inResponseContext) { NSArray *cachedFileURLs = [[inResponseContext objectForKey:kIRWebAPIEngineResponseContextOriginalRequestContext] objectForKey:kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey]; @@ -77,7 +76,7 @@ + (IRWebAPIResponseContextTransformer) defaultCleanUpTemporaryFilesResponseTrans return inParsedResponse; - }) copy] autorelease]; + }) copy]; } diff --git a/IRWebAPIEngine.h b/IRWebAPIEngine.h index eef61b6..1fa078b 100644 --- a/IRWebAPIEngine.h +++ b/IRWebAPIEngine.h @@ -21,7 +21,7 @@ extern NSString * const kIRWebAPIEngineUnderlyingError; @interface IRWebAPIEngine : NSObject @property (nonatomic, readwrite, copy) IRWebAPIResponseParser parser; -@property (nonatomic, readonly, retain) IRWebAPIContext *context; +@property (nonatomic, readonly, retain) IRWebAPIEngineContext *context; @property (nonatomic, readonly, retain) NSMutableArray *globalRequestPreTransformers; @property (nonatomic, readonly, retain) NSMutableDictionary *requestTransformers; @@ -31,7 +31,7 @@ extern NSString * const kIRWebAPIEngineUnderlyingError; @property (nonatomic, readonly, retain) NSMutableDictionary *responseTransformers; @property (nonatomic, readonly, retain) NSMutableArray *globalResponsePostTransformers; -- (id) initWithContext:(IRWebAPIContext *)inContext; +- (id) initWithContext:(IRWebAPIEngineContext *)inContext; - (void) fireAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil validator:(IRWebAPIResposeValidator)inValidator successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler; diff --git a/IRWebAPIEngine.j b/IRWebAPIEngine.j deleted file mode 100644 index 9dc3f09..0000000 --- a/IRWebAPIEngine.j +++ /dev/null @@ -1,436 +0,0 @@ -// IRWebAPIEngine.j -// Evadne Wu at Iridia, 2010 - -@import - - - - - -var kIRWebAPIEngineSerializationSchemes = { - -// TODO: Reference http://www.w3.org/TR/html401/interact/forms.html - - "IRWebAPIEngineSerializationSchemeOrdinaryFlat": function (inDictionary) { - - var returnString = @"", - enumerator = [inDictionary keyEnumerator], - key = nil; - - while (key = [enumerator nextObject]) - returnString += @"&" + encodeURIComponent(key) + @"=" + encodeURIComponent([inDictionary objectForKey:key]); - - return returnString.replace(/^&/, ""); - - } - -}; - - - - - -var kIRWebAPIEngineConnectionTimeoutTimeIntervalUserInfoDictionaryKey = @"IRWebAPIEngineConnectionTimeoutTimeInterval", - kIRWebAPIEnginePrintDebuggingInfoDictionaryKey = @"IRWebAPIEnginePrintDebuggingInfo", - kIRWebAPIEngineSerializationSchemeKeyOrdinaryFlat = "IRWebAPIEngineSerializationSchemeOrdinaryFlat", - kIRWebAPIEngineConnectionDidReceiveDataNotification = @"IRWebAPIEngineConnectionDidReceiveDataNotification", - kIRWebAPIEngineConnectionDidFailNotification = @"IRWebAPIEngineConnectionDidFailNotification"; - - - - - -@class IRWebAPIContext; - - - - - -@implementation IRWebAPIEngine : CPObject { - - IRWebAPIContext context; - id delegate @accessors; - CPMutableSet aliveConnections; - - -// Note. The global transformations could be overriding points for authentication purposes, -// But if you want to do something XSLT’y, do them in argument / response transformations for every method involved. - - CPMutableArray globalArgumentTransformations; // Called on all outgoing method invocations - CPMutableDictionary requestArgumentTransformations; // Key is method name - CPMutableDictionary responseTransformations; // Key is method name - CPMutableArray globalResponseTransformations; // Called on all incoming responses - - CPMutableDictionary successHandlersForConnections; // Key is connection UID - CPMutableDictionary failureHandlersForConnections; // Key is connection UID - - CPMutableDictionary mockResponses; // Key is method name, contains mock JS Objects - - /* (CPString) */ IRWebAPIEngineSerializationSchemeKey serializationScheme @accessors; - - BOOL debugMode; - - Class connectionClass @accessors; - -} - - - - - -+ (IRProtocol) delegateProtocol { - - return [IRProtocol protocolWithSelectorsAndOptionalFlags: - - @selector(transformationForMethodCallNamed:engine:), true, - @selector(transformationForMethodFeedbackNamed:engine:), true - - ]; - -} - - - - - -+ (IRWebAPIEngine) engineWithContext:(IRWebAPIContext)inContext { - - self = [[self alloc] initWithContext:inContext]; if (self == nil) return nil; - - return self; - -} - - - - - -- (IRWebAPIEngine) initWithContext:(IRWebAPIContext)inContext { - - self = [super init]; if (self == nil) return nil; - - context = inContext; - serializationScheme = kIRWebAPIEngineSerializationSchemeKeyOrdinaryFlat; - - globalArgumentTransformations = [CPMutableArray array]; - requestArgumentTransformations = [CPMutableDictionary dictionary]; - - globalResponseTransformations = [CPMutableArray array]; - responseTransformations = [CPMutableDictionary dictionary]; - - successHandlersForConnections = [CPMutableDictionary dictionary]; - failureHandlersForConnections = [CPMutableDictionary dictionary]; - -// connectionClass = [IRJSONPMockConnection class]; - connectionClass = [CPJSONPConnection class]; - - mockResponses = [CPMutableDictionary dictionary]; - - debugMode = ([[[CPBundle bundleForClass:[[[CPApplication sharedApplication] delegate] class]] infoDictionary] objectForKey:kIRWebAPIEnginePrintDebuggingInfoDictionaryKey] || NO); - - return self; - -} - - - - - -- (void) enqueueGlobalArgumentTransformation:(Function)transformation { - - [globalArgumentTransformations addObject:transformation]; - -} - -- (void) enqueueArgumentTransformation:(Function)transformation forMethodNamed:(CPString)methodName { - - [requestArgumentTransformations setObject:transformation forKey:methodName]; - -} - - -- (CPDictionary) transformedArguments:(CPDictionary)inArguments forMethodNamed:(CPString)methodName { - - var requestObject = [inArguments mutableCopy] || [CPMutableDictionary dictionary]; - - [globalArgumentTransformations enumerate: function (inGlobalArgumentTransformation) { - - if (debugMode) CPLog(@"%@: Transforming request: %@", self, requestObject); - requestObject = inGlobalArgumentTransformation(requestObject); - if (debugMode) CPLog(@"%@: Transformed request: %@", self, requestObject); - - }]; - - var specificArgumentTransformation = [requestArgumentTransformations valueForKey:methodName]; - if (specificArgumentTransformation != nil) - requestObject = specificArgumentTransformation(requestObject); - - return requestObject; - -} - - - - - -- (void) enqueueGlobalResponseTransformation:(Function)transformation { - - [globalResponseTransformations addObject:transformation]; - -} - -- (void) enqueueResponseTransformation:(Function)transformation forMethodNamed:(CPString)methodName { - - [responseTransformations setObject:transformation forKey:methodName]; - -} - -- (CPDictionary) transformedResponse:(CPDictionary)inResponse forMethodNamed:(CPString)methodName { - - var responseObject = [inResponse mutableCopy] || [CPMutableDictionary dictionary]; - - [globalResponseTransformations enumerate: function (inGlobalResponseTransformation) { - - if (debugMode) CPLog(@"%@: Transforming response: %@", self, responseObject); - responseObject = inGlobalResponseTransformation(responseObject); - if (debugMode) CPLog(@"%@: Transformed response: %@", self, responseObject); - - }]; - - - - var specificResponseTransformation = [responseTransformations valueForKey:methodName]; - if (specificResponseTransformation != nil) - responseObject = specificResponseTransformation(responseObject); - - return responseObject; - -} - - - - - - - - - - -- (void) enqueueMockResponse:(Object)response forMethodNamed:(CPString)methodName { - - [mockResponses setObject:response forKey:methodName]; - -} - -- (id) mockResponseForMethodNamed:(CPString)methodName { - - return [mockResponses objectForKey:methodName]; - -} - - - - - - - - - - -- (void) fireAPIRequestNamed:(CPString)methodName withArguments:(CPDictionary)inArguments { - - [self fireAPIRequestNamed:methodName withArguments:inArguments onSuccess:nil failure:nil]; - -} - - - - - -- (void) fireAPIRequestNamed:(CPString)methodName withArguments:(CPDictionary)inArguments onSuccess:(Function)callbackOnSuccess failure:(Function)callbackOnFailure { - -// Obviously caching and delegate notifying are not there yet - - [self fireAPIRequestNamed:methodName withArguments:inArguments onSuccess:callbackOnSuccess failure:callbackOnFailure cacheResponse:NO notifyDelegate:NO]; - -} - - - - - -- (void) fireAPIRequestNamed:(CPString)methodName withArguments:(CPDictionary)inArguments onSuccess:(Function)callbackOnSuccess failure:(Function)callbackOnFailure cacheResponse:(BOOL)cacheResponse notifyDelegate:(BOOL)notifyDelegate { - - var argumentsToSend = [self transformedArguments:inArguments forMethodNamed:methodName], - serializer = kIRWebAPIEngineSerializationSchemes[serializationScheme], - isPOSTRequest = ([inArguments valueForKey:@"IRWebAPIKitPOST"] === YES); - - var serializedArguments = serializer(argumentsToSend) + "&callback=${JSONP_CALLBACK}"; - urlToCall = isPOSTRequest ? [context connectionURLForPOSTMethodNamed:methodName] : [context connectionURLForMethodNamed:methodName additions:serializedArguments], - request = [CPURLRequest requestWithURL:urlToCall]; - - if (isPOSTRequest) { - - [request setHTTPMethod:@"POST"]; - [request setValue:"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; - [request setHTTPBody:serializer(argumentsToSend)]; - - } - - if (debugMode) CPLog(@"%@: Using URL %@", self, urlToCall); - - - var connection = nil; - - if (isPOSTRequest){ - - connection = [[CPURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; - connection.irWebAPIEngineShallDeserializeResults = YES; - - } else { - - connection = [[connectionClass alloc] initWithRequest:request callback:nil delegate:self startImmediately:NO]; - - } - - connection.methodName = methodName; - - if (callbackOnSuccess != nil) - [successHandlersForConnections setObject:callbackOnSuccess forKey:[connection UID]]; - - if (callbackOnFailure != nil) - [failureHandlersForConnections setObject:callbackOnFailure forKey:[connection UID]]; - - - [self addConnectionToTheActiveSet:connection]; - - var mockResponseOrNil = [self mockResponseForMethodNamed:methodName]; - if (mockResponseOrNil != null) { - - [self connection:methodName didReceiveData:mockResponseOrNil]; - - return; - - } - - - [connection start]; - - var connectionTimeout /* (CPTimeinterval) */ = parseFloat( - - [[[CPBundle mainBundle] infoDictionary] objectForKey:kIRWebAPIEngineConnectionTimeoutTimeIntervalUserInfoDictionaryKey] - - ) || 10.0; - - [self performSelector:@selector(purgeConnectionAndSendFailureNotificationIfAppropriate:) withObject:connection afterDelay:connectionTimeout]; - -} - - - - - -- (void) connection:(id)connection didReceiveData:(Object)data { - - if (debugMode) CPLog(@"%@: Connection %@ did receive data %@", self, connection, data); - -// Since we might also grab stuff using POST… - if (connection.irWebAPIEngineShallDeserializeResults === YES) - data = [data objectFromJSON]; - - [self removeConnectionFromTheActiveSet:connection]; - - var transformedResponse = [self transformedResponse:[CPDictionary dictionaryWithJSObject:data recursively:YES] forMethodNamed:connection.methodName]; - - if (debugMode) CPLog(@"%@: Connection data is transformed to %@", self, transformedResponse); - - var successHandler = [successHandlersForConnections objectForKey:[connection UID]]; - - if (successHandler) { - - successHandler(transformedResponse); - [successHandlersForConnections removeObjectForKey:[connection UID]]; - - } else { - - [[CPNotificationCenter defaultCenter] postNotificationName:kIRWebAPIEngineConnectionDidReceiveDataNotification object:nil userInfo:transformedResponse]; - - } - -} - - - - - -- (void) connection:(CPJSONPConnection)connection didFailWithError:(CPString)error { - - if (debugMode) CPLog(@"%@: Connection %@ did fail with error %@.", self, connection, error); - - [self removeConnectionFromTheActiveSet:connection]; - - var failureHandler = [failureHandlersForConnections objectForKey:[connection UID]]; - - if (failureHandler) { - - failureHandler(error); - [failureHandlersForConnections removeObjectForKey:[connection UID]]; - - } else { - - [[CPNotificationCenter defaultCenter] postNotificationName:kIRWebAPIEngineConnectionDidFailNotification object:nil userInfo:nil]; - - } - -} - - - - - -- (void) addConnectionToTheActiveSet:(CPJSONPConnection)connection { - - if (aliveConnections == nil) - aliveConnections = [CPMutableSet set]; - - [aliveConnections addObject:connection]; - -} - - - - -- (void) removeConnectionFromTheActiveSet:(CPJSONPConnection)connection { - - [aliveConnections removeObject:connection]; - -} - - - - - -- (void) purgeConnectionAndSendFailureNotificationIfAppropriate:(CPJSONPConnection)connection { - -// If this connection is not in the active set, it has already finished, or failed - - if (![aliveConnections containsObject:connection]) return; - - if (debugMode) CPLog(@"%@: Purging connection %@.", self, connection); - -// Pose as the connection itself and send ourself a delegate message to clean up residue - - [connection cancel]; - [self connection:connection didFailWithError:null]; - -} - - - - - -@end - - - - diff --git a/IRWebAPIEngine.m b/IRWebAPIEngine.m index c11b0e8..76fdafb 100644 --- a/IRWebAPIEngine.m +++ b/IRWebAPIEngine.m @@ -29,7 +29,7 @@ @interface IRWebAPIEngine () -@property (nonatomic, readwrite, retain) IRWebAPIContext *context; +@property (nonatomic, readwrite, retain) IRWebAPIEngineContext *context; @property (nonatomic, readwrite, retain) NSMutableArray *globalRequestPreTransformers; @property (nonatomic, readwrite, retain) NSMutableDictionary *requestTransformers; @@ -86,11 +86,13 @@ @implementation IRWebAPIEngine # pragma mark - # pragma mark Initializationand Memory Management -- (id) initWithContext:(IRWebAPIContext *)inContext { +- (id) initWithContext:(IRWebAPIEngineContext *)inContext { - self = [super init]; if (!self) return nil; + self = [super init]; + if (!self) + return nil; - context = [inContext retain]; + context = inContext; self.globalRequestPreTransformers = [NSMutableArray array]; self.requestTransformers = [NSMutableDictionary dictionary]; @@ -114,21 +116,9 @@ - (id) init { - (void) dealloc { - self.parser = nil; - self.context = nil; - - self.globalRequestPreTransformers = nil; - self.requestTransformers = nil; - self.globalRequestPostTransformers = nil; - - self.globalRequestPostTransformers = nil; - self.responseTransformers = nil; - self.globalRequestPostTransformers = nil; - - dispatch_release(self.sharedDispatchQueue); - self.sharedDispatchQueue = nil; - - [super dealloc]; +#if !OS_OBJECT_USE_OBJC + dispatch_release(sharedDispatchQueue); +#endif } @@ -232,6 +222,8 @@ - (void) enqueueAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictio - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil validator:(IRWebAPIResposeValidator)inValidator successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler { + __weak IRWebAPIEngine *wSelf = self; + [self ensureResponseParserExistence]; void (^retryHandler)(void) = ^ { @@ -249,22 +241,20 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in NSDictionary *finalizedContext = [self requestContextByTransformingContext:[self baseRequestContextWithMethodName:inMethodName arguments:inArgumentsOrNil options:inOptionsOrNil] forMethodNamed:inMethodName]; NSURLRequest *request = [self requestWithContext:finalizedContext]; - + void (^returnedBlock) (void) = ^ { dispatch_async(dispatch_get_main_queue(), ^{ - NSURLConnection *connection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease]; + NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; [self setInternalSuccessHandler: ^ (NSData *inResponse) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - BOOL shouldRetry = NO, notifyDelegate = NO; - NSDictionary *responseContext = [self internalResponseContextForConnection:connection]; - NSDictionary *parsedResponse = [self parsedResponseForData:inResponse withContext:finalizedContext]; - NSDictionary *transformedResponse = [self responseByTransformingResponse:parsedResponse withRequestContext:responseContext forMethodNamed:inMethodName]; + NSDictionary *responseContext = [wSelf internalResponseContextForConnection:connection]; + NSDictionary *parsedResponse = [wSelf parsedResponseForData:inResponse withContext:finalizedContext]; + NSDictionary *transformedResponse = [wSelf responseByTransformingResponse:parsedResponse withRequestContext:responseContext forMethodNamed:inMethodName]; if ((inValidator != nil) && (!inValidator(transformedResponse, responseContext))) { @@ -281,18 +271,16 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in if (shouldRetry) retryHandler(); if (notifyDelegate) notifyDelegateHandler(); - [self cleanUpForConnection:connection]; + [wSelf cleanUpForConnection:connection]; - [pool drain]; - } forConnection:connection]; [self setInternalFailureHandler: ^ { BOOL shouldRetry = NO, notifyDelegate = NO; - NSMutableDictionary *responseContext = [self internalResponseContextForConnection:connection]; - NSDictionary *transformedResopnse = [self responseByTransformingResponse:[NSDictionary dictionary] withRequestContext:responseContext forMethodNamed:inMethodName]; + NSMutableDictionary *responseContext = [wSelf internalResponseContextForConnection:connection]; + NSDictionary *transformedResopnse = [wSelf responseByTransformingResponse:[NSDictionary dictionary] withRequestContext:responseContext forMethodNamed:inMethodName]; if (inFailureHandler) inFailureHandler(transformedResopnse, responseContext, ¬ifyDelegate, &shouldRetry); @@ -300,7 +288,7 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in if (shouldRetry) retryHandler(); if (notifyDelegate) notifyDelegateHandler(); - [self cleanUpForConnection:connection]; + [wSelf cleanUpForConnection:connection]; } forConnection:connection]; @@ -318,7 +306,7 @@ - (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)in }; - return [[returnedBlock copy] autorelease]; + return [returnedBlock copy]; } @@ -407,49 +395,49 @@ - (void) connection:(NSURLConnection *)connection didReceiveAuthenticationChalle - (void) setInternalSuccessHandler:(void (^)(NSData *inResponse))inSuccessHandler forConnection:(NSURLConnection *)inConnection { - objc_setAssociatedObject(inConnection, kIRWebAPIEngineAssociatedSuccessHandler, inSuccessHandler, OBJC_ASSOCIATION_COPY); + objc_setAssociatedObject(inConnection, CFBridgingRetain(kIRWebAPIEngineAssociatedSuccessHandler), inSuccessHandler, OBJC_ASSOCIATION_COPY); } - (void (^)(NSData *inResponse)) internalSuccessHandlerForConnection:(NSURLConnection *)inConnection { - return objc_getAssociatedObject(inConnection, kIRWebAPIEngineAssociatedSuccessHandler); + return objc_getAssociatedObject(inConnection, (__bridge const void *)(kIRWebAPIEngineAssociatedSuccessHandler)); } - (void) setInternalFailureHandler:(void (^)(void))inFailureHandler forConnection:(NSURLConnection *)inConnection { - objc_setAssociatedObject(inConnection, kIRWebAPIEngineAssociatedFailureHandler, inFailureHandler, OBJC_ASSOCIATION_COPY); + objc_setAssociatedObject(inConnection, CFBridgingRetain(kIRWebAPIEngineAssociatedFailureHandler), inFailureHandler, OBJC_ASSOCIATION_COPY); } - (void (^)(void)) internalFailureHandlerForConnection:(NSURLConnection *)inConnection { - return objc_getAssociatedObject(inConnection, kIRWebAPIEngineAssociatedFailureHandler); + return objc_getAssociatedObject(inConnection, (__bridge const void *)(kIRWebAPIEngineAssociatedFailureHandler)); } - (void) setInternalDataStore:(NSMutableData *)inDataStore forConnection:(NSURLConnection *)inConnection { - objc_setAssociatedObject(inConnection, kIRWebAPIEngineAssociatedDataStore, inDataStore, OBJC_ASSOCIATION_RETAIN); + objc_setAssociatedObject(inConnection, (__bridge const void *)(kIRWebAPIEngineAssociatedDataStore), inDataStore, OBJC_ASSOCIATION_RETAIN); } - (NSMutableData *) internalDataStoreForConnection:(NSURLConnection *)inConnection { - return objc_getAssociatedObject(inConnection, kIRWebAPIEngineAssociatedDataStore); + return objc_getAssociatedObject(inConnection, (__bridge const void *)(kIRWebAPIEngineAssociatedDataStore)); } - (void) setInternalResponseContext:(NSMutableDictionary *)inResponseContext forConnection:(NSURLConnection *)inConnection { - objc_setAssociatedObject(inConnection, kIRWebAPIEngineAssociatedResponseContext, inResponseContext, OBJC_ASSOCIATION_RETAIN); + objc_setAssociatedObject(inConnection, (__bridge const void *)(kIRWebAPIEngineAssociatedResponseContext), inResponseContext, OBJC_ASSOCIATION_RETAIN); } - (NSMutableDictionary *) internalResponseContextForConnection:(NSURLConnection *)inConnection { - return objc_getAssociatedObject(inConnection, kIRWebAPIEngineAssociatedResponseContext); + return objc_getAssociatedObject(inConnection, (__bridge const void *)(kIRWebAPIEngineAssociatedResponseContext)); } @@ -524,13 +512,13 @@ - (NSDictionary *) baseRequestContextWithMethodName:(NSString *)inMethodName arg baseURL = baseURL ? baseURL : [self.context baseURLForMethodNamed:inMethodName]; NSMutableDictionary *headerFields = [inOptionsOrNil objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - headerFields = headerFields ? [[headerFields mutableCopy] autorelease] : [NSMutableDictionary dictionary]; + headerFields = headerFields ? [headerFields mutableCopy] : [NSMutableDictionary dictionary]; id httpBody = [inOptionsOrNil objectForKey:kIRWebAPIEngineRequestHTTPBody]; httpBody = httpBody ? httpBody : [NSNull null]; NSString *httpMethod = [inOptionsOrNil objectForKey:kIRWebAPIEngineRequestHTTPMethod]; - httpMethod = httpMethod ? [[httpMethod copy] autorelease] : @"GET"; + httpMethod = httpMethod ? [httpMethod copy] : @"GET"; IRWebAPIResponseParser responseParser = [inOptionsOrNil objectForKey:kIRWebAPIEngineParser]; responseParser = responseParser ? responseParser : self.parser; @@ -555,14 +543,12 @@ - (NSDictionary *) baseRequestContextWithMethodName:(NSString *)inMethodName arg for (id optionValueKey in inOptionsOrNil) [transformedContext setValue:[inOptionsOrNil valueForKey:optionValueKey] forKey:optionValueKey]; - return [[transformedContext copy] autorelease]; + return [transformedContext copy]; } - (NSDictionary *) requestContextByTransformingContext:(NSDictionary *)inContext forMethodNamed:(NSString *)inMethodName { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSMutableArray *allTransformers = [NSMutableArray array]; [allTransformers addObjectsFromArray:self.globalRequestPreTransformers]; @@ -580,17 +566,12 @@ - (NSDictionary *) requestContextByTransformingContext:(NSDictionary *)inContext for (IRWebAPIRequestContextTransformer aTransformer in allTransformers) currentContext = aTransformer(currentContext); - [currentContext retain]; - [pool drain]; - - return [currentContext autorelease]; + return currentContext; } - (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse withRequestContext:(NSDictionary *)inRequestContext forMethodNamed:(NSString *)inMethodName { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSMutableArray *allTransformers = [NSMutableArray array]; [allTransformers addObjectsFromArray:self.globalResponsePreTransformers]; [allTransformers addObjectsFromArray:[self responseTransformersForMethodNamed:inMethodName]]; @@ -601,10 +582,7 @@ - (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse wit for (IRWebAPIResponseContextTransformer aTransformer in allTransformers) currentResponse = aTransformer(currentResponse, inRequestContext); - [currentResponse retain]; - [pool drain]; - - return [currentResponse autorelease]; + return currentResponse; } @@ -614,8 +592,6 @@ - (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse wit - (NSURLRequest *) requestWithContext:(NSDictionary *)inContext { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:IRWebAPIRequestURLWithQueryParameters( (NSURL *)[inContext objectForKey:kIRWebAPIEngineRequestHTTPBaseURL], @@ -636,10 +612,7 @@ - (NSURLRequest *) requestWithContext:(NSDictionary *)inContext { [request setHTTPMethod:[inContext objectForKey:kIRWebAPIEngineRequestHTTPMethod]]; - NSURLRequest *returnedRequest = [request copy]; - [pool drain]; - - return [returnedRequest autorelease]; + return [request copy]; } diff --git a/IRWebAPIContext.h b/IRWebAPIEngineContext.h similarity index 57% rename from IRWebAPIContext.h rename to IRWebAPIEngineContext.h index 0edfd1d..5f0658f 100644 --- a/IRWebAPIContext.h +++ b/IRWebAPIEngineContext.h @@ -9,27 +9,19 @@ #import +@interface IRWebAPIEngineContext : NSObject - - -@interface IRWebAPIContext : NSObject { - - NSURL *baseURL; - -} - -@property (nonatomic, retain, readwrite) NSURL *baseURL; +@property (nonatomic, readonly, copy) NSURL *baseURL; - (id) initWithBaseURL:(NSURL *)inBaseURL; - (NSURL *) baseURLForMethodNamed:(NSString *)inMethodName; - - - - @end +@interface IRWebAPIEngineMutableContext : IRWebAPIEngineContext +@property (nonatomic, readwrite, copy) NSURL *baseURL; +@end diff --git a/IRWebAPIContext.m b/IRWebAPIEngineContext.m similarity index 53% rename from IRWebAPIContext.m rename to IRWebAPIEngineContext.m index b61d91a..079270a 100644 --- a/IRWebAPIContext.m +++ b/IRWebAPIEngineContext.m @@ -6,21 +6,25 @@ // Copyright 2010 Iridia Productions. All rights reserved. // -#import "IRWebAPIContext.h" - +#import "IRWebAPIEngineContext.h" +@interface IRWebAPIEngineContext () +@property (nonatomic, readwrite, copy) NSURL *baseURL; +@end -@implementation IRWebAPIContext -@synthesize baseURL; +@implementation IRWebAPIEngineContext +@synthesize baseURL = _baseURL; - (id) initWithBaseURL:(NSURL *)inBaseURL { - self = [super init]; if (!self) return nil; + self = [super init]; + if (!self) + return nil; - baseURL = [inBaseURL retain]; + _baseURL = [inBaseURL copy]; return self; @@ -32,10 +36,6 @@ - (id) init { } - - - - - (NSURL *) baseURLForMethodNamed:(NSString *)inMethodName { return [NSURL URLWithString:inMethodName relativeToURL:self.baseURL]; @@ -45,5 +45,7 @@ - (NSURL *) baseURLForMethodNamed:(NSString *)inMethodName { @end +@implementation IRWebAPIEngineMutableContext : IRWebAPIEngineContext +@dynamic baseURL; - +@end diff --git a/IRWebAPIGoogleReaderAuthenticator.h b/IRWebAPIGoogleReaderAuthenticator.h deleted file mode 100644 index 0a5215d..0000000 --- a/IRWebAPIGoogleReaderAuthenticator.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// IRWebAPIGoogleReaderAuthenticator.h -// IRWebAPIKit -// -// Created by Evadne Wu on 11/21/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -@class IRWebAPIAuthenticator; -@interface IRWebAPIGoogleReaderAuthenticator : IRWebAPIAuthenticator { - - NSString *authToken; - -} - -- (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess:(IRWebAPIAuthenticatorCallback)successHandler onFailure:(IRWebAPIAuthenticatorCallback)failureHandler; - -@end diff --git a/IRWebAPIGoogleReaderAuthenticator.m b/IRWebAPIGoogleReaderAuthenticator.m deleted file mode 100644 index 5be24d1..0000000 --- a/IRWebAPIGoogleReaderAuthenticator.m +++ /dev/null @@ -1,106 +0,0 @@ -// -// IRWebAPIGoogleReaderAuthenticator.m -// IRWebAPIKit -// -// Created by Evadne Wu on 11/21/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPIKit.h" -#import "IRWebAPIGoogleReaderAuthenticator.h" - -@interface IRWebAPIGoogleReaderAuthenticator () - -@property (nonatomic, retain, readwrite) NSString *authToken; - -@end - - -@implementation IRWebAPIGoogleReaderAuthenticator - -@synthesize authToken; - -- (void) createTransformerBlocks { - - self.globalRequestPreTransformerBlock = [[^ (NSDictionary *inOriginalContext) { - - if (!self.currentCredentials) return inOriginalContext; - if (!self.authToken) return inOriginalContext; - - NSMutableDictionary *transformedContext = [[inOriginalContext mutableCopy] autorelease]; - volatile NSMutableDictionary *headerFields = [transformedContext valueForKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - headerFields = headerFields ? [[headerFields mutableCopy] autorelease] : [NSMutableDictionary dictionary]; - [transformedContext setObject:headerFields forKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - [headerFields setObject:[NSString stringWithFormat:@"GoogleLogin auth=%@", self.authToken] forKey:@"Authorization"]; - - return (NSDictionary *)transformedContext; - - } copy] autorelease]; - - self.globalResponsePreTransformerBlock = [[^ (NSDictionary *inParsedResponse, NSDictionary *inResponseContext) { - - return inParsedResponse; - - } copy] autorelease]; - -} - -- (void) associateWithEngine:(IRWebAPIEngine *)inEngine { - - [self disassociateEngine]; - - self.authToken = nil; - self.engine = inEngine; - - [super associateWithEngine:inEngine]; - -} - -- (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess:(IRWebAPIAuthenticatorCallback)successHandler onFailure:(IRWebAPIAuthenticatorCallback)failureHandler { - - [self.engine fireAPIRequestNamed:@"accounts/ClientLogin" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - -// Does not quite work -// @"HOSTED_OR_GOOGLE", @"accountType", - - @"reader", @"service", - inCredentials.identifier, @"Email", - inCredentials.qualifier, @"Passwd", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIResponseQueryResponseParserMake(), kIRWebAPIEngineParser, - @"POST", kIRWebAPIEngineRequestHTTPMethod, - [NSDictionary dictionaryWithObjectsAndKeys:@"application/x-www-form-urlencoded", @"Content-type", nil], kIRWebAPIEngineRequestHTTPHeaderFields, - - nil] validator: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - if ([inResponseOrNil valueForKey:@"Auth"] == nil) - return NO; - - if ([inResponseOrNil valueForKey:@"Error"]) - return NO; - - return YES; - - } successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - self.authToken = [inResponseOrNil valueForKey:@"Auth"]; - self.currentCredentials = inCredentials; - self.currentCredentials.authenticated = YES; - - if (successHandler) - successHandler(self, YES, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - *outShouldRetry = NO; - - if (failureHandler) - failureHandler(self, NO, outShouldRetry); - - }]; - -} - -@end diff --git a/IRWebAPIGoogleReaderInterface.h b/IRWebAPIGoogleReaderInterface.h deleted file mode 100644 index fd661bc..0000000 --- a/IRWebAPIGoogleReaderInterface.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// IRWebAPIGoogleReaderInterface.h -// IRWebAPIKit -// -// Created by Evadne Wu on 12/1/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPIKit.h" - -@interface IRWebAPIGoogleReaderInterface : IRWebAPIInterface - -@property (nonatomic, readwrite, assign) NSUInteger batchSize; - -- (void) retrieveCurrentUserInfoWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveSubscribedFeedsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveFeedsWithUnreadItemsUsingSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveTagsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveItemsOfFeed:(NSURL *)feedURL crawledAfterDate:(NSDate *)crawledDate excluding:(NSArray *)itemsOrStates successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveItemsWithLabel:(NSString *)aLabelName crawledAfterDate:(NSDate *)crawledDate excluding:(NSArray *)itemsOrStates successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveReadingListItemsCrawledAfterDate:(NSDate *)crawledDate excluding:(NSArray *)itemsOrStates successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveStarredItemsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; -- (void) retrieveSharedItemsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; -- (void) retrieveNotesWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrievePreferencesWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -@end diff --git a/IRWebAPIGoogleReaderInterface.m b/IRWebAPIGoogleReaderInterface.m deleted file mode 100644 index cd0349a..0000000 --- a/IRWebAPIGoogleReaderInterface.m +++ /dev/null @@ -1,220 +0,0 @@ -// -// IRWebAPIGoogleReaderInterface.m -// IRWebAPIKit -// -// Created by Evadne Wu on 12/1/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPIGoogleReaderInterface.h" - - -NSString * const kIRWebAPIGoogleReaderInterfaceBatchSize = @"n"; - - - - - -@interface IRWebAPIGoogleReaderInterface () - -- (NSString *) exclusionStringFromArray:(NSArray *)excludedItemsOrStates; - -@end - -@implementation IRWebAPIGoogleReaderInterface - -@synthesize batchSize; - -- (id) init { - - IRWebAPIContext *googleReaderContext = [[[IRWebAPIContext alloc] initWithBaseURL:[NSURL URLWithString:@"https://www.google.com"]] autorelease]; - IRWebAPIEngine *googleReaderEngine = [[[IRWebAPIEngine alloc] initWithContext:googleReaderContext] autorelease]; - IRWebAPIAuthenticator *googleReaderAuthenticator = [[[IRWebAPIGoogleReaderAuthenticator alloc] initWithEngine:googleReaderEngine] autorelease]; - - googleReaderEngine.parser = IRWebAPIResponseDefaultJSONParserMake(); - - self = [self initWithEngine:googleReaderEngine authenticator:googleReaderAuthenticator]; - if (!self) return nil; - - self.batchSize = 200; - - - [self.engine.globalRequestPreTransformers addObject:[[ ^ (NSDictionary *inOriginalContext) { - - NSMutableDictionary *transformedContext = [[inOriginalContext mutableCopy] autorelease]; - NSMutableDictionary *queryParameters = [transformedContext objectForKey:kIRWebAPIEngineRequestHTTPQueryParameters]; - - if (!queryParameters) { - - queryParameters = [NSMutableDictionary dictionary]; - [transformedContext setObject:queryParameters forKey:kIRWebAPIEngineRequestHTTPQueryParameters]; - - } - - [queryParameters setObject:@"IRWebAPIKit" forKey:@"client"]; - [queryParameters setObject:[NSNumber numberWithDouble:floor([[NSDate date] timeIntervalSince1970])] forKey:@"ck"]; - [queryParameters setObject:@"json" forKey:@"output"]; - - return (NSDictionary *)transformedContext; - - } copy] autorelease]]; - - - return self; - -} - -- (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess:(IRWebAPIAuthenticatorCallback)successHandler onFailure:(IRWebAPIAuthenticatorCallback)failureHandler { - - [self.authenticator authenticateCredentials:inCredentials onSuccess: ^ (IRWebAPIAuthenticator *inAuthenticator, BOOL isAuthenticated, BOOL *inShouldRetry) { - - if (!isAuthenticated) { - - *inShouldRetry = YES; - return; - - } - - if (successHandler) - successHandler(inAuthenticator, isAuthenticated, inShouldRetry); - - } onFailure:failureHandler]; - -} - -- (void) retrieveCurrentUserInfoWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"reader/api/0/user-info" withArguments:nil options:nil validator: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - for (id aKey in [NSArray arrayWithObjects:@"userEmail", @"userId", @"userName", nil]) - if ([inResponseOrNil objectForKey:aKey] == nil) - return NO; - - return YES; - - } successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -- (void) retrieveSubscribedFeedsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"reader/api/0/subscription/list" withArguments:nil options:nil validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - NSLog(@"reader/api/0/subscription/list %@", inResponseOrNil); - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -- (void) retrieveFeedsWithUnreadItemsUsingSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(NO, @"Implement %s", __PRETTY_FUNCTION__); - -} - -- (void) retrieveTagsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(NO, @"Implement %s", __PRETTY_FUNCTION__); - -} - -- (void) retrieveItemsOfFeed:(NSURL *)feedURL crawledAfterDate:(NSDate *)crawledDate excluding:(NSArray *)itemsOrStates successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:[@"reader/api/0/stream/contents/feed/" stringByAppendingString:[feedURL absoluteString]] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSNumber numberWithInt:self.batchSize], kIRWebAPIGoogleReaderInterfaceBatchSize, - [self exclusionStringFromArray:itemsOrStates], @"xt", - @"d", @"r", - - nil] options:nil validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -- (void) retrieveItemsWithLabel:(NSString *)aLabelName crawledAfterDate:(NSDate *)crawledDate excluding:(NSArray *)itemsOrStates successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(NO, @"Implement %s", __PRETTY_FUNCTION__); - -} - -- (void) retrieveReadingListItemsCrawledAfterDate:(NSDate *)crawledDate excluding:(NSArray *)itemsOrStates successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(NO, @"Implement %s", __PRETTY_FUNCTION__); - -} - -- (void) retrieveStarredItemsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(NO, @"Implement %s", __PRETTY_FUNCTION__); - -} - -- (void) retrieveSharedItemsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(NO, @"Implement %s", __PRETTY_FUNCTION__); - -} - -- (void) retrieveNotesWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(NO, @"Implement %s", __PRETTY_FUNCTION__); - -} - -- (void) retrievePreferencesWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"reader/api/0/preference/stream/list" withArguments:nil options:nil validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - - -} - - - - - -- (NSString *) exclusionStringFromArray:(NSArray *)excludedItemsOrStates { - - NSLog(@"Implement %s !", __PRETTY_FUNCTION__); - - return @""; - -} - -@end diff --git a/IRWebAPIHelpers.h b/IRWebAPIHelpers.h index a4e59fc..691b228 100644 --- a/IRWebAPIHelpers.h +++ b/IRWebAPIHelpers.h @@ -24,8 +24,6 @@ extern BOOL IRWebAPIKitValidResponse (id inObject); extern NSString * IRWebAPIKitStringValue (id inObject); -extern id IRWebAPIKitWrapNil(id inObjectOrNil); -extern id IRWebAPIKitNumberOrNull (NSNumber *aNumber); # pragma mark Encoding, Decoding and Conversion diff --git a/IRWebAPIHelpers.m b/IRWebAPIHelpers.m index 57b161e..2c3e4fb 100644 --- a/IRWebAPIHelpers.m +++ b/IRWebAPIHelpers.m @@ -23,8 +23,8 @@ if ([inObject isKindOfClass:[NSString class]]) return (NSString *)inObject; - if ([inObject respondsToSelector:@selector(stringValue)]) - return IRWebAPIKitStringValue([inObject performSelector:@selector(stringValue)]); + if ([inObject isKindOfClass:[NSValue class]]) + return [inObject performSelector:@selector(stringValue)]; return [inObject description]; @@ -38,24 +38,6 @@ BOOL IRWebAPIKitValidResponse (id inObject) { } -id IRWebAPIKitWrapNil(id inObjectOrNil) { - - if (inObjectOrNil == nil) - return [NSNull null]; - - return inObjectOrNil; - -} - -id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { - - if (!(BOOL)[aNumber boolValue]) - return [NSNull null]; - - return aNumber; - -}; - @@ -70,7 +52,7 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { // From Google’s GData Toolkit // http://oauth.net/core/1.0a/#encoding_parameters - CFStringRef originalString = (CFStringRef)inString; + CFStringRef originalString = (__bridge CFStringRef)inString; CFStringRef leaveUnescaped = CFSTR("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-._~"); CFStringRef forceEscaped = CFSTR("%!$&'()*+,/:;=?@"); @@ -81,11 +63,9 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { escapedStr = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, originalString, leaveUnescaped, forceEscaped, kCFStringEncodingUTF8); - [(id)CFMakeCollectable(escapedStr) autorelease]; - } - return (NSString *)escapedStr; + return (NSString *)CFBridgingRelease(escapedStr); } @@ -93,22 +73,13 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { NSString *inString = IRWebAPIKitStringValue(inObject); -// From Google’s GData Toolkit -// http://oauth.net/core/1.0a/#encoding_parameters - - CFStringRef originalString = (CFStringRef)inString; - - CFStringRef unescapedStr = NULL; - - if (inString) { - - unescapedStr = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, originalString, CFSTR(""), kCFStringEncodingUTF8); - - [(id)CFMakeCollectable(unescapedStr) autorelease]; - - } + if (!inString) + return nil; + + // From Google’s GData Toolkit + // http://oauth.net/core/1.0a/#encoding_parameters - return (NSString *)unescapedStr; + return (NSString *)CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (__bridge CFStringRef)inString, CFSTR(""), kCFStringEncodingUTF8)); } @@ -153,7 +124,7 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { } - return [[[NSString alloc] initWithData:buffer encoding:NSASCIIStringEncoding] autorelease]; + return [[NSString alloc] initWithData:buffer encoding:NSASCIIStringEncoding]; } @@ -174,7 +145,7 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { [scanner setCharactersToBeSkipped:nil]; - entityNamesToNumbers = entityNamesToNumbers ? entityNamesToNumbers : [IRWebAPIKitXMLEntityNumbersFromNames() retain]; + entityNamesToNumbers = entityNamesToNumbers ? entityNamesToNumbers : IRWebAPIKitXMLEntityNumbersFromNames(); NSString* (^scanEntityNumber) (NSScanner **inScanner) = ^ (NSScanner **inScanner) { @@ -200,8 +171,6 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { NSString *unknownEntity = @""; [scanner scanUpToCharactersFromSet:boundaryCharacterSet intoString:&unknownEntity]; - IRWebAPIKitLog(@"Expected numeric character entity but got &#%@%@;", xForHex, unknownEntity); - return (NSString *)[NSString stringWithFormat:@"&#%@%@", xForHex, unknownEntity]; }; @@ -262,7 +231,7 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault); if (!theUUID) return nil; - uuid = [(NSString *)CFUUIDCreateString(kCFAllocatorDefault, theUUID) autorelease]; + uuid = (NSString *)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, theUUID)); CFRelease(theUUID); return [NSString stringWithFormat:@"%@-%@", IRWebAPIKitTimestamp(), uuid]; @@ -278,8 +247,6 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { NSString * IRWebAPIKitOAuthSignatureBaseStringMake (NSString *inHTTPMethod, NSURL *inBaseURL, NSDictionary *inQueryParameters) { - IRWebAPIKitLog(@"IRWebAPIKitOAuthSignatureBaseStringMake -> %@ %@ %@", inHTTPMethod, inBaseURL, inQueryParameters); - NSString * (^uriEncode) (NSString *) = ^ NSString * (NSString *inString) { return IRWebAPIKitRFC3986EncodedStringMake(inString); @@ -315,45 +282,27 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { } - IRWebAPIKitLog(@"IRWebAPIKitOAuthSignatureBaseStringMake -> %@", returnedString); - return returnedString; } NSString * IRWebAPIKitHMACSHA1 (NSString *inConsumerSecret, NSString *inTokenSecret, NSString *inPayload) { - IRWebAPIKitLog(@"IRWebAPIKitHMACSHA1 -> %@ %@ %@", inConsumerSecret, inTokenSecret, inPayload); - -// From Google’s GData Toolkit + // From Google’s GData Toolkit NSString *encodedConsumerSecret = IRWebAPIKitRFC3986EncodedStringMake(inConsumerSecret); + if (!encodedConsumerSecret) + encodedConsumerSecret = @""; + NSString *encodedTokenSecret = IRWebAPIKitRFC3986EncodedStringMake(inTokenSecret); + if (!encodedTokenSecret) + encodedTokenSecret = @""; - NSString *key = [NSString stringWithFormat:@"%@&%@", - - encodedConsumerSecret ? encodedConsumerSecret : @"", - encodedTokenSecret ? encodedTokenSecret : @"" - - ]; - + NSString *key = [NSString stringWithFormat:@"%@&%@", encodedConsumerSecret, encodedTokenSecret]; NSMutableData *sigData = [NSMutableData dataWithLength:CC_SHA1_DIGEST_LENGTH]; - CCHmac( - - kCCHmacAlgSHA1, - - [key UTF8String], [key length], - [inPayload UTF8String], [inPayload length], - [sigData mutableBytes] - - ); - - NSString *returnedString = IRWebAPIKitBase64StringFromNSDataMake(sigData); - - IRWebAPIKitLog(@"IRWebAPIKitHMACSHA1 -> %@", returnedString); - - return returnedString; + CCHmac(kCCHmacAlgSHA1, [key UTF8String], [key length], [inPayload UTF8String], [inPayload length], [sigData mutableBytes]); + return IRWebAPIKitBase64StringFromNSDataMake(sigData); } @@ -369,7 +318,7 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { if (!inExtension) return nil; - CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)inExtension, NULL); + CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)CFBridgingRetain(inExtension), NULL); if(!UTI) return nil; @@ -380,7 +329,7 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { if (!registeredType) return nil; - return [(NSString *)registeredType autorelease]; + return (NSString *)CFBridgingRelease(registeredType); } diff --git a/IRWebAPIInterface+Validators.m b/IRWebAPIInterface+Validators.m index 005f535..2746813 100644 --- a/IRWebAPIInterface+Validators.m +++ b/IRWebAPIInterface+Validators.m @@ -13,36 +13,13 @@ @implementation IRWebAPIInterface (Validators) + (IRWebAPIResposeValidator) defaultNoErrorValidator { - return [[(^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { + return [(^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { NSHTTPURLResponse *response = (NSHTTPURLResponse *)[inResponseContext objectForKey:kIRWebAPIEngineResponseContextURLResponse]; - - BOOL noError = ([response statusCode] == 200); - - if (!noError) { - - IRWebAPIKitLog(@"Error: %x %@", [response statusCode], [[response class] localizedStringForStatusCode:[response statusCode]]); - - if ([inResponseOrNil isEqual:[NSNull null]]) { - - return NO; - - } - - id errorContent = nil; - if ((errorContent = [inResponseOrNil valueForKeyPath:@"error"])) { - - IRWebAPIKitLog(@"Error from Server: %@", errorContent); - - } - - return NO; - } - - return YES; + return (response.statusCode == 200); - }) copy] autorelease]; + }) copy]; } diff --git a/IRWebAPIInterface.h b/IRWebAPIInterface.h index 317be8b..d0aa90a 100644 --- a/IRWebAPIInterface.h +++ b/IRWebAPIInterface.h @@ -8,7 +8,7 @@ #import -@class IRWebAPIEngine, IRWebAPIAuthenticator, IRWebAPIContext; +@class IRWebAPIEngine, IRWebAPIAuthenticator, IRWebAPIEngineContext; @interface IRWebAPIInterface : NSObject diff --git a/IRWebAPIInterface.m b/IRWebAPIInterface.m index 7d9879c..7307012 100644 --- a/IRWebAPIInterface.m +++ b/IRWebAPIInterface.m @@ -8,29 +8,27 @@ #import "IRWebAPIKit.h" - - - - @implementation IRWebAPIInterface -@synthesize engine, authenticator; - -- (id) init { - - return [self initWithEngine:nil authenticator:nil]; - -} +@synthesize engine = _engine, authenticator = _authenticator; - (id) initWithEngine:(IRWebAPIEngine *)inEngine authenticator:(IRWebAPIAuthenticator *)inAuthenticator { - self = [super init]; if (!self) return nil; + self = [super init]; + if (!self) + return nil; - engine = [inEngine retain]; - authenticator = [inAuthenticator retain]; + _engine = inEngine; + _authenticator = inAuthenticator; return self; } +- (id) init { + + return [self initWithEngine:nil authenticator:nil]; + +} + @end diff --git a/IRWebAPIKit.h b/IRWebAPIKit.h index bb9e63c..e554f93 100644 --- a/IRWebAPIKit.h +++ b/IRWebAPIKit.h @@ -7,23 +7,6 @@ // - - - -#if 0 && defined(DEBUG) - - #define IRWebAPIKitLog( s, ... ) NSLog( @"<%s : (%d)> %@",__FUNCTION__, __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] ) - -#else - - #define IRWebAPIKitLog( s, ... ) - -#endif - - - - - #import "IRWebAPIKitDefines.h" #import "IRWebAPIResponseParser.h" @@ -31,7 +14,7 @@ #import "IRWebAPIHelpers.h" #import "IRWebAPIEngine.h" -#import "IRWebAPIContext.h" +#import "IRWebAPIEngineContext.h" #import "IRWebAPIAuthenticator.h" #import "IRWebAPICredentials.h" #import "IRWebAPIInterface.h" @@ -42,14 +25,9 @@ #import "IRWebAPIInterfaceURLShortening.h" -#import "IRWebAPIGoogleReaderAuthenticator.h" #import "IRWebAPIXOAuthAuthenticator.h" -#import "IRWebAPITwitterInterface.h" -#import "IRWebAPIGoogleReaderInterface.h" - #import "IRWebAPIImageStorageProvider.h" -#import "IRWebAPITwitPicInterface.h" #import "IRRemoteResourcesManager.h" diff --git a/IRWebAPIKit.j b/IRWebAPIKit.j deleted file mode 100644 index 57e9e3b..0000000 --- a/IRWebAPIKit.j +++ /dev/null @@ -1,34 +0,0 @@ -// IRWebAPIKit.j -// Evadne Wu at Iridia, 2010' - - - - - - @import - @import - @import - - @import "IRWebAPIEngine.j" - @import "IRWebAPIContext.j" - -// Working on… - @import "IRSiteReachability.j" - -// Mock! - @import "IRWebAPIMockJSONPConnection.j" - - - - - - // Time to talk about how this tool works: - // - // 1. Be flat in what you send, be three-dimensional in what you get. - // 2. Give JSON, take JSON. Give Objects, take Objects. - // 3. Register transformations in your initializer. Don’t do ad-hoc transformations. - - - - - \ No newline at end of file diff --git a/IRWebAPIKit.xcodeproj/project.pbxproj b/IRWebAPIKit.xcodeproj/project.pbxproj index 609d1e3..6f0322d 100644 --- a/IRWebAPIKit.xcodeproj/project.pbxproj +++ b/IRWebAPIKit.xcodeproj/project.pbxproj @@ -17,16 +17,11 @@ FF25FA301299406200975BE3 /* IRWebAPICredentials.m in Sources */ = {isa = PBXBuildFile; fileRef = FF25FA2E1299406200975BE3 /* IRWebAPICredentials.m */; }; FF25FA331299406800975BE3 /* IRWebAPIAuthenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = FF25FA311299406800975BE3 /* IRWebAPIAuthenticator.h */; }; FF25FA341299406800975BE3 /* IRWebAPIAuthenticator.m in Sources */ = {isa = PBXBuildFile; fileRef = FF25FA321299406800975BE3 /* IRWebAPIAuthenticator.m */; }; - FF25FA7F129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = FF25FA7D129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.h */; }; - FF25FA80129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.m in Sources */ = {isa = PBXBuildFile; fileRef = FF25FA7E129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.m */; }; FF25FCCA12996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = FF25FCC812996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.h */; }; FF25FCCB12996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.m in Sources */ = {isa = PBXBuildFile; fileRef = FF25FCC912996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.m */; }; FF25FD7E129971EC00975BE3 /* IRWebAPIHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = FF25FD7D129971EC00975BE3 /* IRWebAPIHelpers.h */; }; FF32C80B150F3A4200A9FE52 /* IRWebAPIKitTest.h in Headers */ = {isa = PBXBuildFile; fileRef = FF32C809150F3A4200A9FE52 /* IRWebAPIKitTest.h */; }; FF32C80C150F3A4200A9FE52 /* IRWebAPIKitTest.m in Sources */ = {isa = PBXBuildFile; fileRef = FF32C80A150F3A4200A9FE52 /* IRWebAPIKitTest.m */; }; - FF32C80F150F3C5E00A9FE52 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF32C80E150F3C5E00A9FE52 /* MobileCoreServices.framework */; }; - FF3DD7BA1348839D000C6380 /* IRWebAPITwitterInterface+Friendships.h in Headers */ = {isa = PBXBuildFile; fileRef = FF3DD7B81348839D000C6380 /* IRWebAPITwitterInterface+Friendships.h */; }; - FF3DD7BB1348839D000C6380 /* IRWebAPITwitterInterface+Friendships.m in Sources */ = {isa = PBXBuildFile; fileRef = FF3DD7B91348839D000C6380 /* IRWebAPITwitterInterface+Friendships.m */; }; FF45629312D057D6000239DC /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF45629212D057D6000239DC /* SenTestingKit.framework */; }; FF45629712D057F1000239DC /* libIRWebAPIKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FF7408241296A8D200571D46 /* libIRWebAPIKit.a */; }; FF45635B12D06A46000239DC /* IRWebAPIKitEntityDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = FF45635A12D06A46000239DC /* IRWebAPIKitEntityDefines.h */; }; @@ -36,15 +31,11 @@ FF460D09149CF80B00DB7F0B /* IRWebAPIEngine+ExternalTransforms.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF5AC731470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m */; }; FF460DB4149CFF3F00DB7F0B /* IRRemoteResourceDownloadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = FFB882B514234CBF00DA2876 /* IRRemoteResourceDownloadOperation.h */; }; FF47A29B12A6486900AF729F /* IRWebAPIInterfaceAuthenticating.h in Headers */ = {isa = PBXBuildFile; fileRef = FF47A29A12A6486900AF729F /* IRWebAPIInterfaceAuthenticating.h */; }; - FF48661612A6329900B75591 /* IRWebAPIGoogleReaderInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = FF48661412A6329900B75591 /* IRWebAPIGoogleReaderInterface.h */; }; - FF48661712A6329900B75591 /* IRWebAPIGoogleReaderInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = FF48661512A6329900B75591 /* IRWebAPIGoogleReaderInterface.m */; }; FF4FCC6212F4637F0037F33C /* IRWebAPIResponseParser.m in Sources */ = {isa = PBXBuildFile; fileRef = FF4FCC6112F4637F0037F33C /* IRWebAPIResponseParser.m */; }; - FF5147BE12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.h in Headers */ = {isa = PBXBuildFile; fileRef = FF5147BC12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.h */; }; - FF5147BF12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.m in Sources */ = {isa = PBXBuildFile; fileRef = FF5147BD12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.m */; }; FF59A39B1441C94500BB1FDC /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF59A3571441C8B600BB1FDC /* Cocoa.framework */; }; FF59A3A11441C94500BB1FDC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FF59A39F1441C94500BB1FDC /* InfoPlist.strings */; }; FF59A3B11441C9C800BB1FDC /* IRWebAPIKitDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB7F12EC5CB80037E930 /* IRWebAPIKitDefines.m */; }; - FF59A3B21441C9CD00BB1FDC /* IRWebAPIContext.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7408981296B06F00571D46 /* IRWebAPIContext.m */; }; + FF59A3B21441C9CD00BB1FDC /* IRWebAPIEngineContext.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7408981296B06F00571D46 /* IRWebAPIEngineContext.m */; }; FF59A3B31441C9CD00BB1FDC /* IRWebAPIEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7408461296A94900571D46 /* IRWebAPIEngine.m */; }; FF59A3B41441C9D100BB1FDC /* IRWebAPIEngine+LocalCaching.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB4112EC59040037E930 /* IRWebAPIEngine+LocalCaching.m */; }; FF59A3B51441C9D100BB1FDC /* IRWebAPIEngine+FormMultipart.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB7212EC5C060037E930 /* IRWebAPIEngine+FormMultipart.m */; }; @@ -57,19 +48,15 @@ FF59A3BC1441C9F400BB1FDC /* IRRemoteResourceDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = FFB882B614234CBF00DA2876 /* IRRemoteResourceDownloadOperation.m */; }; FF59A3BD1441C9F400BB1FDC /* IRWebAPIInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = FF896A6A12A5666D00AE2AF3 /* IRWebAPIInterface.m */; }; FF59A3BE1441C9F400BB1FDC /* IRWebAPIInterface+Validators.m in Sources */ = {isa = PBXBuildFile; fileRef = FF1B23CC12F3400F00B30B99 /* IRWebAPIInterface+Validators.m */; }; - FF609D1F12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = FF609D1D12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.h */; }; - FF609D2012E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = FF609D1E12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.m */; }; FF74082B1296A8E000571D46 /* IRWebAPIKit.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7408291296A8E000571D46 /* IRWebAPIKit.h */; }; FF7408471296A94900571D46 /* IRWebAPIEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7408451296A94900571D46 /* IRWebAPIEngine.h */; }; FF7408481296A94900571D46 /* IRWebAPIEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7408461296A94900571D46 /* IRWebAPIEngine.m */; }; - FF7408991296B06F00571D46 /* IRWebAPIContext.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7408971296B06F00571D46 /* IRWebAPIContext.h */; }; - FF74089A1296B06F00571D46 /* IRWebAPIContext.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7408981296B06F00571D46 /* IRWebAPIContext.m */; }; + FF7408991296B06F00571D46 /* IRWebAPIEngineContext.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7408971296B06F00571D46 /* IRWebAPIEngineContext.h */; }; + FF74089A1296B06F00571D46 /* IRWebAPIEngineContext.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7408981296B06F00571D46 /* IRWebAPIEngineContext.m */; }; FF740CAA1296EB0C00571D46 /* IRWebAPIResponseParser.h in Headers */ = {isa = PBXBuildFile; fileRef = FF740CA91296EB0C00571D46 /* IRWebAPIResponseParser.h */; }; FF7EB68A1467B876002718DC /* IRWebAPIEngine+FormURLEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7EB6881467B876002718DC /* IRWebAPIEngine+FormURLEncoding.h */; }; FF7EB68B1467B876002718DC /* IRWebAPIEngine+FormURLEncoding.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7EB6891467B876002718DC /* IRWebAPIEngine+FormURLEncoding.m */; }; FF7F44A712EDB36E00DC1628 /* IRWebAPIInterfaceOAuthEchoReliance.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7F44A612EDB36E00DC1628 /* IRWebAPIInterfaceOAuthEchoReliance.h */; }; - FF7F44B712EDB44400DC1628 /* IRWebAPITwitPicInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7F44B512EDB44400DC1628 /* IRWebAPITwitPicInterface.h */; }; - FF7F44B812EDB44400DC1628 /* IRWebAPITwitPicInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7F44B612EDB44400DC1628 /* IRWebAPITwitPicInterface.m */; }; FF7F44C412EDB52800DC1628 /* IRWebAPIImageStorageProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7F44C312EDB52800DC1628 /* IRWebAPIImageStorageProvider.h */; }; FF7F44E112EDB74F00DC1628 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF7F44E012EDB74F00DC1628 /* CoreFoundation.framework */; }; FF7F44E312EDB74F00DC1628 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF7F44E212EDB74F00DC1628 /* Foundation.framework */; }; @@ -77,8 +64,6 @@ FF7F44E912EDB74F00DC1628 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF7F44E812EDB74F00DC1628 /* SystemConfiguration.framework */; }; FF896A6B12A5666D00AE2AF3 /* IRWebAPIInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = FF896A6912A5666D00AE2AF3 /* IRWebAPIInterface.h */; }; FF896A6C12A5666D00AE2AF3 /* IRWebAPIInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = FF896A6A12A5666D00AE2AF3 /* IRWebAPIInterface.m */; }; - FF896DD512A567FA00AE2AF3 /* IRWebAPITwitterInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = FF896DD312A567FA00AE2AF3 /* IRWebAPITwitterInterface.h */; }; - FF896DD612A567FA00AE2AF3 /* IRWebAPITwitterInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = FF896DD412A567FA00AE2AF3 /* IRWebAPITwitterInterface.m */; }; FF8974E212A57F3800AE2AF3 /* IRWebAPIInterfaceXOAuthAuthenticating.h in Headers */ = {isa = PBXBuildFile; fileRef = FF8974E112A57F3800AE2AF3 /* IRWebAPIInterfaceXOAuthAuthenticating.h */; }; FF9AFB4212EC59040037E930 /* IRWebAPIEngine+LocalCaching.h in Headers */ = {isa = PBXBuildFile; fileRef = FF9AFB4012EC59040037E930 /* IRWebAPIEngine+LocalCaching.h */; }; FF9AFB4312EC59040037E930 /* IRWebAPIEngine+LocalCaching.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB4112EC59040037E930 /* IRWebAPIEngine+LocalCaching.m */; }; @@ -87,25 +72,12 @@ FF9AFB7412EC5C060037E930 /* IRWebAPIEngine+FormMultipart.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB7212EC5C060037E930 /* IRWebAPIEngine+FormMultipart.m */; }; FF9AFB8012EC5CB80037E930 /* IRWebAPIKitDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB7F12EC5CB80037E930 /* IRWebAPIKitDefines.m */; }; FF9AFBF312EC5E9F0037E930 /* IRWebAPIKitDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB7F12EC5CB80037E930 /* IRWebAPIKitDefines.m */; }; - FFAA4351134A8CA600341FAE /* IRWebAPITwitterInterface+User.h in Headers */ = {isa = PBXBuildFile; fileRef = FFAA434F134A8CA600341FAE /* IRWebAPITwitterInterface+User.h */; }; - FFAA4352134A8CA600341FAE /* IRWebAPITwitterInterface+User.m in Sources */ = {isa = PBXBuildFile; fileRef = FFAA4350134A8CA600341FAE /* IRWebAPITwitterInterface+User.m */; }; FFB882B714234CBF00DA2876 /* IRRemoteResourceDownloadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = FFB882B514234CBF00DA2876 /* IRRemoteResourceDownloadOperation.h */; }; FFB882B814234CBF00DA2876 /* IRRemoteResourceDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = FFB882B614234CBF00DA2876 /* IRRemoteResourceDownloadOperation.m */; }; - FFC41B9112B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.h in Headers */ = {isa = PBXBuildFile; fileRef = FFC41B8F12B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.h */; }; - FFC41B9212B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.m in Sources */ = {isa = PBXBuildFile; fileRef = FFC41B9012B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.m */; }; - FFDA9D0A13278C4500546B66 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFDA9D0913278C4500546B66 /* MobileCoreServices.framework */; }; + FFDB8EFD15943C7800FA7E9B /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFDB8EFC15943C7800FA7E9B /* MobileCoreServices.framework */; }; + FFDB8EFE15943C8100FA7E9B /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFDB8EFC15943C7800FA7E9B /* MobileCoreServices.framework */; }; FFF5AC741470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h in Headers */ = {isa = PBXBuildFile; fileRef = FFF5AC721470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h */; }; FFF5AC751470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF5AC731470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m */; }; - FFF90E1C12E3805D00464897 /* IRWebAPITwitterInterface+Lists.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF90C9512E3768C00464897 /* IRWebAPITwitterInterface+Lists.m */; }; - FFF90E1D12E3805D00464897 /* IRWebAPITwitterInterface+Validators.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF90D0A12E37D0400464897 /* IRWebAPITwitterInterface+Validators.m */; }; - FFF90E1E12E3807700464897 /* IRWebAPITwitterInterface+Validators.h in Headers */ = {isa = PBXBuildFile; fileRef = FFF90D0912E37D0400464897 /* IRWebAPITwitterInterface+Validators.h */; }; - FFF90E1F12E3807700464897 /* IRWebAPITwitterInterface+Validators.m in Headers */ = {isa = PBXBuildFile; fileRef = FFF90D0A12E37D0400464897 /* IRWebAPITwitterInterface+Validators.m */; }; - FFF90E2012E3807700464897 /* IRWebAPITwitterInterface.m in Headers */ = {isa = PBXBuildFile; fileRef = FF896DD412A567FA00AE2AF3 /* IRWebAPITwitterInterface.m */; }; - FFF90E2112E3807700464897 /* IRWebAPITwitterInterface+Timeline.m in Headers */ = {isa = PBXBuildFile; fileRef = FF5147BD12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.m */; }; - FFF90E2212E3807700464897 /* IRWebAPITwitterInterface+Lists.h in Headers */ = {isa = PBXBuildFile; fileRef = FFF90C9412E3768C00464897 /* IRWebAPITwitterInterface+Lists.h */; }; - FFF90E2312E3807700464897 /* IRWebAPITwitterInterface+Lists.m in Headers */ = {isa = PBXBuildFile; fileRef = FFF90C9512E3768C00464897 /* IRWebAPITwitterInterface+Lists.m */; }; - FFF90E2412E3807700464897 /* IRWebAPITwitterInterface+Geo.m in Headers */ = {isa = PBXBuildFile; fileRef = FFC41B9012B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.m */; }; - FFF90E2512E3807700464897 /* IRWebAPIGoogleReaderInterface.m in Headers */ = {isa = PBXBuildFile; fileRef = FF48661512A6329900B75591 /* IRWebAPIGoogleReaderInterface.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -129,16 +101,11 @@ FF25FA2E1299406200975BE3 /* IRWebAPICredentials.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPICredentials.m; sourceTree = ""; }; FF25FA311299406800975BE3 /* IRWebAPIAuthenticator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIAuthenticator.h; sourceTree = ""; }; FF25FA321299406800975BE3 /* IRWebAPIAuthenticator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIAuthenticator.m; sourceTree = ""; }; - FF25FA7D129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIGoogleReaderAuthenticator.h; sourceTree = ""; }; - FF25FA7E129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIGoogleReaderAuthenticator.m; sourceTree = ""; }; FF25FCC812996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIXOAuthAuthenticator.h; sourceTree = ""; }; FF25FCC912996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIXOAuthAuthenticator.m; sourceTree = ""; }; FF25FD7D129971EC00975BE3 /* IRWebAPIHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIHelpers.h; sourceTree = ""; }; FF32C809150F3A4200A9FE52 /* IRWebAPIKitTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIKitTest.h; sourceTree = ""; }; FF32C80A150F3A4200A9FE52 /* IRWebAPIKitTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIKitTest.m; sourceTree = ""; }; - FF32C80E150F3C5E00A9FE52 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; }; - FF3DD7B81348839D000C6380 /* IRWebAPITwitterInterface+Friendships.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPITwitterInterface+Friendships.h"; sourceTree = ""; }; - FF3DD7B91348839D000C6380 /* IRWebAPITwitterInterface+Friendships.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPITwitterInterface+Friendships.m"; sourceTree = ""; }; FF45627812D05708000239DC /* IRWebAPIKitTest.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IRWebAPIKitTest.octest; sourceTree = BUILT_PRODUCTS_DIR; }; FF45627912D05708000239DC /* IRWebAPIKitTest-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "IRWebAPIKitTest-Info.plist"; sourceTree = ""; }; FF45629212D057D6000239DC /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; @@ -146,11 +113,7 @@ FF45635C12D06A50000239DC /* IRWebAPIKitEntityDefinesHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIKitEntityDefinesHeader.h; sourceTree = ""; }; FF45637712D07653000239DC /* IRWebAPIKitEntityDefinesFooter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIKitEntityDefinesFooter.h; sourceTree = ""; }; FF47A29A12A6486900AF729F /* IRWebAPIInterfaceAuthenticating.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIInterfaceAuthenticating.h; sourceTree = ""; }; - FF48661412A6329900B75591 /* IRWebAPIGoogleReaderInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIGoogleReaderInterface.h; sourceTree = ""; }; - FF48661512A6329900B75591 /* IRWebAPIGoogleReaderInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIGoogleReaderInterface.m; sourceTree = ""; }; FF4FCC6112F4637F0037F33C /* IRWebAPIResponseParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIResponseParser.m; sourceTree = ""; }; - FF5147BC12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPITwitterInterface+Timeline.h"; sourceTree = ""; }; - FF5147BD12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPITwitterInterface+Timeline.m"; sourceTree = ""; }; FF59A3571441C8B600BB1FDC /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; FF59A35A1441C8B600BB1FDC /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; FF59A35B1441C8B600BB1FDC /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; @@ -159,26 +122,16 @@ FF59A39E1441C94500BB1FDC /* IRWebAPIKitX-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "IRWebAPIKitX-Info.plist"; sourceTree = ""; }; FF59A3A01441C94500BB1FDC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; FF59A3A21441C94500BB1FDC /* IRWebAPIKitX-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IRWebAPIKitX-Prefix.pch"; sourceTree = ""; }; - FF609D1D12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPITwitterInterface+DirectMessages.h"; sourceTree = ""; }; - FF609D1E12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPITwitterInterface+DirectMessages.m"; sourceTree = ""; }; - FF74081A1296A89500571D46 /* IRSiteReachability.j */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = IRSiteReachability.j; sourceTree = ""; }; - FF74081B1296A89500571D46 /* IRWebAPIContext.j */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = IRWebAPIContext.j; sourceTree = ""; }; - FF74081C1296A89500571D46 /* IRWebAPIEngine.j */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = IRWebAPIEngine.j; sourceTree = ""; }; - FF74081D1296A89500571D46 /* IRWebAPIKit.j */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = IRWebAPIKit.j; sourceTree = ""; }; - FF74081E1296A89500571D46 /* IRWebAPIMockJSONPConnection.j */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = IRWebAPIMockJSONPConnection.j; sourceTree = ""; }; - FF74081F1296A89500571D46 /* IRWebAPIModel.j */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = IRWebAPIModel.j; sourceTree = ""; }; FF7408241296A8D200571D46 /* libIRWebAPIKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libIRWebAPIKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; FF7408291296A8E000571D46 /* IRWebAPIKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIKit.h; sourceTree = ""; }; FF7408451296A94900571D46 /* IRWebAPIEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIEngine.h; sourceTree = ""; }; FF7408461296A94900571D46 /* IRWebAPIEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIEngine.m; sourceTree = ""; }; - FF7408971296B06F00571D46 /* IRWebAPIContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIContext.h; sourceTree = ""; }; - FF7408981296B06F00571D46 /* IRWebAPIContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIContext.m; sourceTree = ""; }; + FF7408971296B06F00571D46 /* IRWebAPIEngineContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIEngineContext.h; sourceTree = ""; }; + FF7408981296B06F00571D46 /* IRWebAPIEngineContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIEngineContext.m; sourceTree = ""; }; FF740CA91296EB0C00571D46 /* IRWebAPIResponseParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIResponseParser.h; sourceTree = ""; }; FF7EB6881467B876002718DC /* IRWebAPIEngine+FormURLEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPIEngine+FormURLEncoding.h"; sourceTree = ""; }; FF7EB6891467B876002718DC /* IRWebAPIEngine+FormURLEncoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPIEngine+FormURLEncoding.m"; sourceTree = ""; }; FF7F44A612EDB36E00DC1628 /* IRWebAPIInterfaceOAuthEchoReliance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIInterfaceOAuthEchoReliance.h; sourceTree = ""; }; - FF7F44B512EDB44400DC1628 /* IRWebAPITwitPicInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPITwitPicInterface.h; sourceTree = ""; }; - FF7F44B612EDB44400DC1628 /* IRWebAPITwitPicInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPITwitPicInterface.m; sourceTree = ""; }; FF7F44C312EDB52800DC1628 /* IRWebAPIImageStorageProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIImageStorageProvider.h; sourceTree = ""; }; FF7F44E012EDB74F00DC1628 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; FF7F44E212EDB74F00DC1628 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -186,8 +139,6 @@ FF7F44E812EDB74F00DC1628 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; FF896A6912A5666D00AE2AF3 /* IRWebAPIInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIInterface.h; sourceTree = ""; }; FF896A6A12A5666D00AE2AF3 /* IRWebAPIInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIInterface.m; sourceTree = ""; }; - FF896DD312A567FA00AE2AF3 /* IRWebAPITwitterInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPITwitterInterface.h; sourceTree = ""; }; - FF896DD412A567FA00AE2AF3 /* IRWebAPITwitterInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPITwitterInterface.m; sourceTree = ""; }; FF8974E112A57F3800AE2AF3 /* IRWebAPIInterfaceXOAuthAuthenticating.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIInterfaceXOAuthAuthenticating.h; sourceTree = ""; }; FF9AFB4012EC59040037E930 /* IRWebAPIEngine+LocalCaching.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPIEngine+LocalCaching.h"; sourceTree = ""; }; FF9AFB4112EC59040037E930 /* IRWebAPIEngine+LocalCaching.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPIEngine+LocalCaching.m"; sourceTree = ""; }; @@ -195,20 +146,12 @@ FF9AFB7112EC5C060037E930 /* IRWebAPIEngine+FormMultipart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPIEngine+FormMultipart.h"; sourceTree = ""; }; FF9AFB7212EC5C060037E930 /* IRWebAPIEngine+FormMultipart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPIEngine+FormMultipart.m"; sourceTree = ""; }; FF9AFB7F12EC5CB80037E930 /* IRWebAPIKitDefines.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIKitDefines.m; sourceTree = ""; }; - FFAA434F134A8CA600341FAE /* IRWebAPITwitterInterface+User.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPITwitterInterface+User.h"; sourceTree = ""; }; - FFAA4350134A8CA600341FAE /* IRWebAPITwitterInterface+User.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPITwitterInterface+User.m"; sourceTree = ""; }; FFB882B514234CBF00DA2876 /* IRRemoteResourceDownloadOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRRemoteResourceDownloadOperation.h; sourceTree = ""; }; FFB882B614234CBF00DA2876 /* IRRemoteResourceDownloadOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRRemoteResourceDownloadOperation.m; sourceTree = ""; }; - FFC41B8F12B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPITwitterInterface+Geo.h"; sourceTree = ""; }; - FFC41B9012B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPITwitterInterface+Geo.m"; sourceTree = ""; }; - FFDA9D0913278C4500546B66 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; }; + FFDB8EFC15943C7800FA7E9B /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; FFE2607212D084CB001AF1AF /* IRWebAPIKitEntityDefinesGenerator.rb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.ruby; path = IRWebAPIKitEntityDefinesGenerator.rb; sourceTree = ""; }; FFF5AC721470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPIEngine+ExternalTransforms.h"; sourceTree = ""; }; FFF5AC731470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPIEngine+ExternalTransforms.m"; sourceTree = ""; }; - FFF90C9412E3768C00464897 /* IRWebAPITwitterInterface+Lists.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPITwitterInterface+Lists.h"; sourceTree = ""; }; - FFF90C9512E3768C00464897 /* IRWebAPITwitterInterface+Lists.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPITwitterInterface+Lists.m"; sourceTree = ""; }; - FFF90D0912E37D0400464897 /* IRWebAPITwitterInterface+Validators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPITwitterInterface+Validators.h"; sourceTree = ""; }; - FFF90D0A12E37D0400464897 /* IRWebAPITwitterInterface+Validators.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPITwitterInterface+Validators.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -218,7 +161,7 @@ files = ( FF45629712D057F1000239DC /* libIRWebAPIKit.a in Frameworks */, FF45629312D057D6000239DC /* SenTestingKit.framework in Frameworks */, - FF32C80F150F3C5E00A9FE52 /* MobileCoreServices.framework in Frameworks */, + FFDB8EFE15943C8100FA7E9B /* MobileCoreServices.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -234,11 +177,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - FFDA9D0A13278C4500546B66 /* MobileCoreServices.framework in Frameworks */, FF7F44E112EDB74F00DC1628 /* CoreFoundation.framework in Frameworks */, FF7F44E312EDB74F00DC1628 /* Foundation.framework in Frameworks */, FF7F44E712EDB74F00DC1628 /* Security.framework in Frameworks */, FF7F44E912EDB74F00DC1628 /* SystemConfiguration.framework in Frameworks */, + FFDB8EFD15943C7800FA7E9B /* MobileCoreServices.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -250,10 +193,10 @@ children = ( FF7F44E012EDB74F00DC1628 /* CoreFoundation.framework */, FF7F44E212EDB74F00DC1628 /* Foundation.framework */, - FFDA9D0913278C4500546B66 /* MobileCoreServices.framework */, FF7F44E612EDB74F00DC1628 /* Security.framework */, FF7F44E812EDB74F00DC1628 /* SystemConfiguration.framework */, FF59A3571441C8B600BB1FDC /* Cocoa.framework */, + FFDB8EFC15943C7800FA7E9B /* MobileCoreServices.framework */, FF59A3591441C8B600BB1FDC /* Other Frameworks */, ); name = Frameworks; @@ -298,26 +241,22 @@ FF25FA7B129944C200975BE3 /* Engine & Foundation */ = { isa = PBXGroup; children = ( - FF7408971296B06F00571D46 /* IRWebAPIContext.h */, - FF7408981296B06F00571D46 /* IRWebAPIContext.m */, + FF7408971296B06F00571D46 /* IRWebAPIEngineContext.h */, + FF7408981296B06F00571D46 /* IRWebAPIEngineContext.m */, FF7408451296A94900571D46 /* IRWebAPIEngine.h */, FF7408461296A94900571D46 /* IRWebAPIEngine.m */, - FF9AFB5B12EC5A560037E930 /* IRWebAPIEngine Additions */, + FF9AFB4012EC59040037E930 /* IRWebAPIEngine+LocalCaching.h */, + FF9AFB4112EC59040037E930 /* IRWebAPIEngine+LocalCaching.m */, + FF9AFB7112EC5C060037E930 /* IRWebAPIEngine+FormMultipart.h */, + FF9AFB7212EC5C060037E930 /* IRWebAPIEngine+FormMultipart.m */, + FF7EB6881467B876002718DC /* IRWebAPIEngine+FormURLEncoding.h */, + FF7EB6891467B876002718DC /* IRWebAPIEngine+FormURLEncoding.m */, + FFF5AC721470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h */, + FFF5AC731470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m */, ); name = "Engine & Foundation"; sourceTree = ""; }; - FF25FA7C129944D000975BE3 /* Google Reader */ = { - isa = PBXGroup; - children = ( - FF25FA7D129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.h */, - FF25FA7E129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.m */, - FF48661412A6329900B75591 /* IRWebAPIGoogleReaderInterface.h */, - FF48661512A6329900B75591 /* IRWebAPIGoogleReaderInterface.m */, - ); - name = "Google Reader"; - sourceTree = ""; - }; FF45628512D05732000239DC /* Test */ = { isa = PBXGroup; children = ( @@ -360,7 +299,6 @@ FF74080C1296A88400571D46 = { isa = PBXGroup; children = ( - FF32C80E150F3C5E00A9FE52 /* MobileCoreServices.framework */, FF9AFB4B12EC597C0037E930 /* IRWebAPIKitDefines.h */, FF9AFB7F12EC5CB80037E930 /* IRWebAPIKitDefines.m */, FF7408291296A8E000571D46 /* IRWebAPIKit.h */, @@ -370,26 +308,12 @@ FF0E93DE132BAFA200A316E1 /* Remote Resources Handling */, FF896B5812A5667A00AE2AF3 /* Interfacing Wrapper */, FF45628512D05732000239DC /* Test */, - FF7408191296A88B00571D46 /* Cappuccino */, FF59A39C1441C94500BB1FDC /* IRWebAPIKitX */, FF0E93DD132BAF9200A316E1 /* Frameworks */, FF7408251296A8D200571D46 /* Products */, ); sourceTree = ""; }; - FF7408191296A88B00571D46 /* Cappuccino */ = { - isa = PBXGroup; - children = ( - FF74081A1296A89500571D46 /* IRSiteReachability.j */, - FF74081B1296A89500571D46 /* IRWebAPIContext.j */, - FF74081C1296A89500571D46 /* IRWebAPIEngine.j */, - FF74081D1296A89500571D46 /* IRWebAPIKit.j */, - FF74081E1296A89500571D46 /* IRWebAPIMockJSONPConnection.j */, - FF74081F1296A89500571D46 /* IRWebAPIModel.j */, - ); - name = Cappuccino; - sourceTree = ""; - }; FF7408251296A8D200571D46 /* Products */ = { isa = PBXGroup; children = ( @@ -400,15 +324,6 @@ name = Products; sourceTree = ""; }; - FF7F44D512EDB66500DC1628 /* TwitPic */ = { - isa = PBXGroup; - children = ( - FF7F44B512EDB44400DC1628 /* IRWebAPITwitPicInterface.h */, - FF7F44B612EDB44400DC1628 /* IRWebAPITwitPicInterface.m */, - ); - name = TwitPic; - sourceTree = ""; - }; FF896B5812A5667A00AE2AF3 /* Interfacing Wrapper */ = { isa = PBXGroup; children = ( @@ -421,51 +336,10 @@ FF8974E112A57F3800AE2AF3 /* IRWebAPIInterfaceXOAuthAuthenticating.h */, FF0E874012B9F41C00DF571E /* IRWebAPIInterfaceURLShortening.h */, FF7F44C312EDB52800DC1628 /* IRWebAPIImageStorageProvider.h */, - FF896DD212A567ED00AE2AF3 /* Twitter */, - FF25FA7C129944D000975BE3 /* Google Reader */, - FF7F44D512EDB66500DC1628 /* TwitPic */, ); name = "Interfacing Wrapper"; sourceTree = ""; }; - FF896DD212A567ED00AE2AF3 /* Twitter */ = { - isa = PBXGroup; - children = ( - FF896DD312A567FA00AE2AF3 /* IRWebAPITwitterInterface.h */, - FF896DD412A567FA00AE2AF3 /* IRWebAPITwitterInterface.m */, - FFF90D0912E37D0400464897 /* IRWebAPITwitterInterface+Validators.h */, - FFF90D0A12E37D0400464897 /* IRWebAPITwitterInterface+Validators.m */, - FF5147BC12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.h */, - FF5147BD12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.m */, - FF609D1D12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.h */, - FF609D1E12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.m */, - FFF90C9412E3768C00464897 /* IRWebAPITwitterInterface+Lists.h */, - FFF90C9512E3768C00464897 /* IRWebAPITwitterInterface+Lists.m */, - FFAA434F134A8CA600341FAE /* IRWebAPITwitterInterface+User.h */, - FFAA4350134A8CA600341FAE /* IRWebAPITwitterInterface+User.m */, - FF3DD7B81348839D000C6380 /* IRWebAPITwitterInterface+Friendships.h */, - FF3DD7B91348839D000C6380 /* IRWebAPITwitterInterface+Friendships.m */, - FFC41B8F12B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.h */, - FFC41B9012B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.m */, - ); - name = Twitter; - sourceTree = ""; - }; - FF9AFB5B12EC5A560037E930 /* IRWebAPIEngine Additions */ = { - isa = PBXGroup; - children = ( - FF9AFB4012EC59040037E930 /* IRWebAPIEngine+LocalCaching.h */, - FF9AFB4112EC59040037E930 /* IRWebAPIEngine+LocalCaching.m */, - FF9AFB7112EC5C060037E930 /* IRWebAPIEngine+FormMultipart.h */, - FF9AFB7212EC5C060037E930 /* IRWebAPIEngine+FormMultipart.m */, - FF7EB6881467B876002718DC /* IRWebAPIEngine+FormURLEncoding.h */, - FF7EB6891467B876002718DC /* IRWebAPIEngine+FormURLEncoding.m */, - FFF5AC721470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h */, - FFF5AC731470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m */, - ); - name = "IRWebAPIEngine Additions "; - sourceTree = ""; - }; FFE2607C12D0858A001AF1AF /* XML Entity Definitions */ = { isa = PBXGroup; children = ( @@ -494,11 +368,10 @@ files = ( FF74082B1296A8E000571D46 /* IRWebAPIKit.h in Headers */, FF7408471296A94900571D46 /* IRWebAPIEngine.h in Headers */, - FF7408991296B06F00571D46 /* IRWebAPIContext.h in Headers */, + FF7408991296B06F00571D46 /* IRWebAPIEngineContext.h in Headers */, FF740CAA1296EB0C00571D46 /* IRWebAPIResponseParser.h in Headers */, FF25FA2F1299406200975BE3 /* IRWebAPICredentials.h in Headers */, FF25FA331299406800975BE3 /* IRWebAPIAuthenticator.h in Headers */, - FF25FA7F129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.h in Headers */, FF25FCCA12996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.h in Headers */, FF25FD7E129971EC00975BE3 /* IRWebAPIHelpers.h in Headers */, FF896A6B12A5666D00AE2AF3 /* IRWebAPIInterface.h in Headers */, @@ -508,29 +381,13 @@ FF45635B12D06A46000239DC /* IRWebAPIKitEntityDefines.h in Headers */, FF45635D12D06A50000239DC /* IRWebAPIKitEntityDefinesHeader.h in Headers */, FF45637812D07653000239DC /* IRWebAPIKitEntityDefinesFooter.h in Headers */, - FF896DD512A567FA00AE2AF3 /* IRWebAPITwitterInterface.h in Headers */, - FFF90E1E12E3807700464897 /* IRWebAPITwitterInterface+Validators.h in Headers */, - FFF90E1F12E3807700464897 /* IRWebAPITwitterInterface+Validators.m in Headers */, - FFF90E2012E3807700464897 /* IRWebAPITwitterInterface.m in Headers */, - FF5147BE12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.h in Headers */, - FFF90E2112E3807700464897 /* IRWebAPITwitterInterface+Timeline.m in Headers */, - FFF90E2212E3807700464897 /* IRWebAPITwitterInterface+Lists.h in Headers */, - FFF90E2312E3807700464897 /* IRWebAPITwitterInterface+Lists.m in Headers */, - FFC41B9112B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.h in Headers */, - FFF90E2412E3807700464897 /* IRWebAPITwitterInterface+Geo.m in Headers */, - FF48661612A6329900B75591 /* IRWebAPIGoogleReaderInterface.h in Headers */, - FFF90E2512E3807700464897 /* IRWebAPIGoogleReaderInterface.m in Headers */, - FF609D1F12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.h in Headers */, FF9AFB4212EC59040037E930 /* IRWebAPIEngine+LocalCaching.h in Headers */, FF9AFB4C12EC597C0037E930 /* IRWebAPIKitDefines.h in Headers */, FF9AFB7312EC5C060037E930 /* IRWebAPIEngine+FormMultipart.h in Headers */, FF7F44A712EDB36E00DC1628 /* IRWebAPIInterfaceOAuthEchoReliance.h in Headers */, - FF7F44B712EDB44400DC1628 /* IRWebAPITwitPicInterface.h in Headers */, FF7F44C412EDB52800DC1628 /* IRWebAPIImageStorageProvider.h in Headers */, FF1B23CD12F3400F00B30B99 /* IRWebAPIInterface+Validators.h in Headers */, FF0E93E9132BB07000A316E1 /* IRRemoteResourcesManager.h in Headers */, - FF3DD7BA1348839D000C6380 /* IRWebAPITwitterInterface+Friendships.h in Headers */, - FFAA4351134A8CA600341FAE /* IRWebAPITwitterInterface+User.h in Headers */, FFB882B714234CBF00DA2876 /* IRRemoteResourceDownloadOperation.h in Headers */, FF7EB68A1467B876002718DC /* IRWebAPIEngine+FormURLEncoding.h in Headers */, FFF5AC741470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h in Headers */, @@ -672,7 +529,7 @@ buildActionMask = 2147483647; files = ( FF59A3B11441C9C800BB1FDC /* IRWebAPIKitDefines.m in Sources */, - FF59A3B21441C9CD00BB1FDC /* IRWebAPIContext.m in Sources */, + FF59A3B21441C9CD00BB1FDC /* IRWebAPIEngineContext.m in Sources */, FF59A3B31441C9CD00BB1FDC /* IRWebAPIEngine.m in Sources */, FF59A3B41441C9D100BB1FDC /* IRWebAPIEngine+LocalCaching.m in Sources */, FF59A3B51441C9D100BB1FDC /* IRWebAPIEngine+FormMultipart.m in Sources */, @@ -696,28 +553,17 @@ files = ( FF9AFBF312EC5E9F0037E930 /* IRWebAPIKitDefines.m in Sources */, FF896A6C12A5666D00AE2AF3 /* IRWebAPIInterface.m in Sources */, - FF74089A1296B06F00571D46 /* IRWebAPIContext.m in Sources */, - FF896DD612A567FA00AE2AF3 /* IRWebAPITwitterInterface.m in Sources */, + FF74089A1296B06F00571D46 /* IRWebAPIEngineContext.m in Sources */, FF25FA341299406800975BE3 /* IRWebAPIAuthenticator.m in Sources */, FF25FA301299406200975BE3 /* IRWebAPICredentials.m in Sources */, - FF25FA80129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.m in Sources */, FF25FCCB12996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.m in Sources */, FF7408481296A94900571D46 /* IRWebAPIEngine.m in Sources */, - FF48661712A6329900B75591 /* IRWebAPIGoogleReaderInterface.m in Sources */, - FFC41B9212B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.m in Sources */, - FF5147BF12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.m in Sources */, - FFF90E1C12E3805D00464897 /* IRWebAPITwitterInterface+Lists.m in Sources */, - FFF90E1D12E3805D00464897 /* IRWebAPITwitterInterface+Validators.m in Sources */, - FF609D2012E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.m in Sources */, FF9AFB4312EC59040037E930 /* IRWebAPIEngine+LocalCaching.m in Sources */, FF9AFB7412EC5C060037E930 /* IRWebAPIEngine+FormMultipart.m in Sources */, FF0D4C0B12ED96E500D9B97D /* IRWebAPIHelpers.m in Sources */, - FF7F44B812EDB44400DC1628 /* IRWebAPITwitPicInterface.m in Sources */, FF1B23CE12F3400F00B30B99 /* IRWebAPIInterface+Validators.m in Sources */, FF4FCC6212F4637F0037F33C /* IRWebAPIResponseParser.m in Sources */, FF0E93EA132BB07000A316E1 /* IRRemoteResourcesManager.m in Sources */, - FF3DD7BB1348839D000C6380 /* IRWebAPITwitterInterface+Friendships.m in Sources */, - FFAA4352134A8CA600341FAE /* IRWebAPITwitterInterface+User.m in Sources */, FFB882B814234CBF00DA2876 /* IRRemoteResourceDownloadOperation.m in Sources */, FF7EB68B1467B876002718DC /* IRWebAPIEngine+FormURLEncoding.m in Sources */, FFF5AC751470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m in Sources */, @@ -756,6 +602,7 @@ "\"$(SDKROOT)/Developer/Library/Frameworks\"", "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", "\"$(SDKROOT)$(DEVELOPER_FRAMEWORKS_DIR)\"", + "\"$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks\"", ); GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; @@ -790,6 +637,7 @@ FRAMEWORK_SEARCH_PATHS = ( "\"$(SDKROOT)/Developer/Library/Frameworks\"", "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", + "\"$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks\"", ); GCC_ENABLE_OBJC_EXCEPTIONS = YES; INFOPLIST_FILE = "IRWebAPIKitTest-Info.plist"; @@ -874,6 +722,8 @@ FF74080F1296A88400571D46 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; COPY_PHASE_STRIP = NO; GCC_C_LANGUAGE_STANDARD = c99; GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; @@ -887,6 +737,8 @@ FF7408101296A88400571D46 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; COPY_PHASE_STRIP = YES; GCC_C_LANGUAGE_STANDARD = c99; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; @@ -904,6 +756,7 @@ COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; PRODUCT_NAME = IRWebAPIKit; SDKROOT = iphoneos; }; @@ -917,6 +770,7 @@ COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_OPTIMIZATION_LEVEL = 0; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; PRODUCT_NAME = IRWebAPIKit; SDKROOT = iphoneos; ZERO_LINK = NO; diff --git a/IRWebAPIKitDefines.h b/IRWebAPIKitDefines.h index 0d0d624..8b3a471 100644 --- a/IRWebAPIKitDefines.h +++ b/IRWebAPIKitDefines.h @@ -8,28 +8,8 @@ #import - - - - -#ifndef __IRWebAPIKitDefines__ -#define __IRWebAPIKitDefines__ - -typedef enum { - - IRWebAPIInterfaceCallbackStyleConcatenatedCallback, // if writing framework, use this one - IRWebAPIInterfaceCallbackStyleManyCallbacks // app code and proof of concepts can use this - -} IRWebAPIInterfaceCallbackStyle; - -#endif - - - - - @class IRWebAPIEngine; -@class IRWebAPIContext; +@class IRWebAPIEngineContext; @class IRWebAPIAuthenticator; @class IRWebAPIInterface; diff --git a/IRWebAPIMockJSONPConnection.j b/IRWebAPIMockJSONPConnection.j deleted file mode 100644 index eecc2a6..0000000 --- a/IRWebAPIMockJSONPConnection.j +++ /dev/null @@ -1,115 +0,0 @@ -// IRWebAPIMockJSONPConnection.j -// Evadne Wu at Iridia, 2010 - -@import - -kIRWebAPIMockEndpointGeneralException = @"IRWebAPIMockEndpointGeneralException"; - - - - - -// Notice that we also will probably set a different timeout tolerance for the API engine. -// The timeout here is set for mockup purposes only. - -var kIRJSONPMockConnectionTimeoutDefaultTimeInterval = 15.0, - kIRJSONPMockConnectionTimeoutTimeIntervalInfoDictionaryKey = @"IRJSONPMockConnectionTimeoutDefaultTimeInterval", - kIRJSONPMockConnectionTimeoutDefaultProbability = 0.05, - kIRJSONPMockConnectionTimeoutProbabilityInfoDictionaryKey = @"IRJSONPMockConnectionTimeoutProbability"; - - - - - -@implementation IRJSONPMockConnection : CPJSONPConnection { - - CPMutableDictionary requestHandlers; - - -// Simulated timeout - - CPTimeInterval simulatedTimeoutInterval; - float simulatedTimeoutProbability; - - -// Simulated error - Object simulatedErroneousResponse; - float simulatedErroneousResponseProbability; - -} - - - - - -- (IRWebAPIMockJSONPConnection) initWithRequest:(CPURLRequest)aRequest callback:(CPString)aString delegate:(id)aDelegate startImmediately:(BOOL)shouldStartImmediately { - - if (shouldStartImmediately) - [CPException raise:kIRWebAPIMockEndpointGeneralException reason:[CPString stringWithFormat:@"To use a mocked connection, startImmediately must be set to false because it works with the monkey-patched connection.methodName property."]]; - - self = [super initWithRequest:aRequest callback:aString delegate:aDelegate startImmediately:NO]; - - - var infoDict = [[CPBundle mainBundle] infoDictionary]; - - simulatedTimeoutInterval = [infoDict objectForKey:kIRJSONPMockConnectionTimeoutTimeIntervalInfoDictionaryKey] || kIRJSONPMockConnectionTimeoutDefaultTimeInterval; - - simulatedTimeoutProbability = [infoDict objectForKey:kIRJSONPMockConnectionTimeoutProbabilityInfoDictionaryKey] || kIRJSONPMockConnectionTimeoutDefaultProbability; - - return self; -} - - - - - -- (void) start { - - CPLog(@"self.methodName is %@", self.methodName); - - if ([self shouldSimulateFailure]) { - - CPLog(@"Simulating a connection failure"); - - } else { - - CPLog(@"Simulating a successful connection"); - - } - -} - - - - - -- (void) mockRequestNamed:(CPString)requestName withHandler:(Function)handler { - - if ([requestHandlers objectForKey:requestName] !== nil) - [CPException raise:kIRWebAPIMockEndpointGeneralException reason:[CPString stringWithFormat:@"Mock handler for request named %@ already exists", requestName]]; - - [requestHandlers addObject:handler forKey:requestName]; - -} - - - - - -- (BOOL) shouldSimulateFailure { - - if (Math.random() < simulatedTimeoutProbability) return YES; - - return NO; - -} - - - - - -@end - - - - diff --git a/IRWebAPIModel.j b/IRWebAPIModel.j deleted file mode 100644 index af957cf..0000000 --- a/IRWebAPIModel.j +++ /dev/null @@ -1,87 +0,0 @@ -// IRWebAPIModel.j -// Evadne Wu at Iridia, 2010 - - - - - -@implementation IRWebAPIModel : CPObject { - - BOOL loading; - - id delegate @accessors; - -} - - - - - -+ (IRProtocol) irDelegateProtocol { - - return [IRProtocol protocolWithSelectorsAndOptionalFlags: - - @selector(model:didFinishLoadingWithData:), false, - @selector(model:didFailLoadingWithError:), false, - @selector(model:shouldReloadFromCachedData:), true - - ]; - -} - - - - - -+ (CPString) methodName { - - return nil; - -} - -+ (Function) argumentTransformation { - - return nil; - -} - -+ (Function) responseTransformation { - - return nil; - -} - - - - - -- (IRWebAPIModel) init { - - self = [super init]; if (self == nil) return nil; - - loading = NO; - - return self; - -} - - - - - -- (void) reloadData { - - return; - -} - - - - - - - - - - -@end \ No newline at end of file diff --git a/IRWebAPIOperation.h b/IRWebAPIOperation.h new file mode 100644 index 0000000..5b5ce7d --- /dev/null +++ b/IRWebAPIOperation.h @@ -0,0 +1,13 @@ +// +// IRWebAPIOperation.h +// IRWebAPIKit +// +// Created by Evadne Wu on 6/22/12. +// +// + +#import + +@interface IRWebAPIOperation : NSOperation + +@end diff --git a/IRWebAPIOperation.m b/IRWebAPIOperation.m new file mode 100644 index 0000000..7c2cf59 --- /dev/null +++ b/IRWebAPIOperation.m @@ -0,0 +1,13 @@ +// +// IRWebAPIOperation.m +// IRWebAPIKit +// +// Created by Evadne Wu on 6/22/12. +// +// + +#import "IRWebAPIOperation.h" + +@implementation IRWebAPIOperation + +@end diff --git a/IRWebAPIResponseParser.m b/IRWebAPIResponseParser.m index 7145f85..cf1631b 100644 --- a/IRWebAPIResponseParser.m +++ b/IRWebAPIResponseParser.m @@ -12,6 +12,20 @@ +NSDictionary * IRWebAPIResponseDictionarize (id incomingObject) { + + if (!incomingObject) + return (id)nil; + + if (![incomingObject isKindOfClass:[NSDictionary class]]) + return [NSDictionary dictionaryWithObject:incomingObject forKey:@"response"]; + + return (id)incomingObject; + +} + + + IRWebAPIResponseParser IRWebAPIResponseDefaultParserMake () { // Simply tucks the returned data into a dictionary @@ -21,13 +35,13 @@ IRWebAPIResponseParser IRWebAPIResponseDefaultParserMake () { return [NSDictionary dictionaryWithObjectsAndKeys: inData, @"response", - [[[NSString alloc] initWithData:inData encoding:NSUTF8StringEncoding] autorelease], @"responseText", + [[NSString alloc] initWithData:inData encoding:NSUTF8StringEncoding], @"responseText", nil]; }; - return [[defaultParser copy] autorelease]; + return [defaultParser copy]; } @@ -37,205 +51,67 @@ IRWebAPIResponseParser IRWebAPIResponseDefaultParserMake () { IRWebAPIResponseParser IRWebAPIResponseQueryResponseParserMake () { -// Parses UTF8 String Data Like: -// -// Key=URL_Encoded_Value -// Another_Key=Another_Encoded_Value - - NSDictionary * (^queryResponseParser) (NSData *) = ^ NSDictionary * (NSData *inData) { - - NSString *responseString = [[[NSString alloc] initWithData:inData encoding:NSUTF8StringEncoding] autorelease]; - - NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@"([^=&\n\r]+)=([^=&\n\r]+)[\n\r&]?" options:NSRegularExpressionCaseInsensitive error:nil]; - - NSMutableDictionary *returnedResponse = [NSMutableDictionary dictionary]; + // Parses UTF8 String Data Like: + // + // Key=URL_Encoded_Value + // Another_Key=Another_Encoded_Value + + static IRWebAPIResponseParser parserBlock = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ - @try { + parserBlock = [^ NSDictionary * (NSData *inData) { - [expression enumerateMatchesInString:responseString options:0 range:NSMakeRange(0, [responseString length]) usingBlock: ^ (NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { + NSString *responseString = [[NSString alloc] initWithData:inData encoding:NSUTF8StringEncoding]; - [returnedResponse setObject:[responseString substringWithRange:[result rangeAtIndex:2]] forKey:[responseString substringWithRange:[result rangeAtIndex:1]]]; + NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@"([^=&\n\r]+)=([^=&\n\r]+)[\n\r&]?" options:NSRegularExpressionCaseInsensitive error:nil]; - }]; - - } @catch (NSException * e) { + NSMutableDictionary *returnedResponse = [NSMutableDictionary dictionary]; - NSLog(@"IRWebAPIResponseQueryResponseParser encountered an exception while parsing response. Returning empty dictionary."); + @try { - return [NSDictionary dictionary]; + [expression enumerateMatchesInString:responseString options:0 range:NSMakeRange(0, [responseString length]) usingBlock: ^ (NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { + + [returnedResponse setObject:[responseString substringWithRange:[result rangeAtIndex:2]] forKey:[responseString substringWithRange:[result rangeAtIndex:1]]]; + + }]; - } + } @catch (NSException * e) { + + NSLog(@"IRWebAPIResponseQueryResponseParser encountered an exception while parsing response. Returning empty dictionary."); + + return [NSDictionary dictionary]; + + } - return returnedResponse; - - }; + return returnedResponse; + + } copy]; + + }); - return [[queryResponseParser copy] autorelease]; + return parserBlock; } - - - IRWebAPIResponseParser IRWebAPIResponseDefaultJSONParserMake () { - static id parserInstance = nil; static IRWebAPIResponseParser parserBlock = nil; + static dispatch_once_t onceToken; - if (parserBlock) - return parserBlock; - - NSDictionary * (^dictionarize)(id) = ^ (id incomingObject) { - - if (!incomingObject) - return (id)nil; - - if (![incomingObject isKindOfClass:[NSDictionary class]]) - return [NSDictionary dictionaryWithObject:incomingObject forKey:@"response"]; - - return (id)incomingObject; - - }; - - Class classJSONKit = NSClassFromString(@"JSONDecoder"); - if (classJSONKit) { - - parserInstance = [classJSONKit performSelector:@selector(decoder)]; - [parserInstance retain]; - - parserBlock = (IRWebAPIResponseParser)[[^ (NSData *incomingData) { - return dictionarize([parserInstance performSelector:@selector(objectWithData:) withObject:incomingData]); - } copy] autorelease]; + dispatch_once(&onceToken, ^{ - return parserBlock; + parserBlock = [^ (NSData *incomingData) { - } - - Class classTouchJSON = NSClassFromString(@"CJSONDeserializer"); - if (classTouchJSON) { - - parserInstance = [classTouchJSON performSelector:@selector(deserializer)]; - [parserInstance retain]; - - parserBlock = (IRWebAPIResponseParser)[[^ (NSData *incomingData) { - - SEL selDeserialize = @selector(deserialize:error:); - id incomingObject; - - NSError *error = nil; - NSError **errorPointer = &error; - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[parserInstance methodSignatureForSelector:selDeserialize]]; - - [invocation setTarget:parserInstance]; - [invocation setSelector:selDeserialize]; - [invocation setArgument:&incomingData atIndex:2]; - [invocation setArgument:&errorPointer atIndex:3]; - [invocation invoke]; - [invocation getReturnValue:&incomingObject]; - - return dictionarize(incomingObject); - - } copy] autorelease]; - - return parserBlock; - - } - - return IRWebAPIResponseDefaultParserMake(); - -} - -IRWebAPIResponseParser IRWebAPIResponseDefaultXMLParserMake () { - - static IRWebAPIResponseParser parserBlock = nil; - - if (parserBlock) - return parserBlock; - - // __block NSDictionary * (^dictionarize)(id); - // dictionarize = [[^ (id incomingObject) { - // - // if (!incomingObject) - // return (NSDictionary *)nil; - // - // NSArray *children = [incomingObject performSelector:@selector(children)]; - // NSArray *attributes = [incomingObject respondsToSelector:@selector(attributes)] ? [incomingObject performSelector:@selector(attributes)] : nil; - // - // NSMutableDictionary *returnedDictionary = [NSMutableDictionary dictionary]; - // - // [returnedDictionary setObject:[incomingObject performSelector:@selector(name)] forKey:@"name"]; - // - // if ([children count]) { - // - // NSMutableArray *childrenDictionaries = [NSMutableArray array]; - // - // for (id element in children) - // [childrenDictionaries addObject:dictionarize(element)]; - // - // [returnedDictionary setObject:childrenDictionaries forKey:@"children"]; - // - // } - // - // if ([attributes count]) { - // - // NSMutableArray *attributesDictionaries = [NSMutableArray array]; - // - // for (id element in attributes) - // [attributesDictionaries addObject:dictionarize(element)]; - // - // [returnedDictionary setObject:attributesDictionaries forKey:@"attributes"]; - // - // } - // - // [returnedDictionary setObject:[incomingObject performSelector:@selector(stringValue)] forKey:@"value"]; - // - // return returnedDictionary; - // - // } copy] autorelease]; - // - // [dictionarize retain]; - - Class classTouchXMLDocument = NSClassFromString(@"CXMLDocument"); - if (classTouchXMLDocument) { - - parserBlock = (IRWebAPIResponseParser)[[^ (NSData *incomingData) { - - SEL selInstantiate = @selector(initWithData:encoding:options:error:); - id incomingObject = nil; + id results = [NSJSONSerialization JSONObjectWithData:incomingData options:NSJSONReadingAllowFragments error:nil]; - NSError *error = nil; - NSError **errorPointer = &error; + return IRWebAPIResponseDictionarize(results); - id parserInstance = [classTouchXMLDocument performSelector:@selector(alloc)]; - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[parserInstance methodSignatureForSelector:selInstantiate]]; - - NSStringEncoding stringEncoding = NSUTF8StringEncoding; - NSUInteger options = 0; - - [invocation setTarget:parserInstance]; - [invocation setSelector:selInstantiate]; - [invocation setArgument:&incomingData atIndex:2]; - [invocation setArgument:&stringEncoding atIndex:3]; - [invocation setArgument:&options atIndex:4]; - [invocation setArgument:&errorPointer atIndex:5]; - [invocation invoke]; - [invocation getReturnValue:&incomingObject]; - - return [NSDictionary dictionaryWithObjectsAndKeys: - - incomingObject, @"object", - incomingData, @"data", - // dictionarize([incomingObject performSelector:@selector(rootElement)]), @"interpretation", + } copy]; - nil]; + }); - } copy] autorelease]; - - return parserBlock; - - } + return parserBlock; - return IRWebAPIResponseDefaultParserMake(); - } diff --git a/IRWebAPITwitPicInterface.h b/IRWebAPITwitPicInterface.h deleted file mode 100644 index c7f163a..0000000 --- a/IRWebAPITwitPicInterface.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// IRWebAPITwitPicInterface.h -// IRWebAPIKit -// -// Created by Evadne Wu on 1/24/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPIKit.h" - - -@interface IRWebAPITwitPicInterface : IRWebAPIInterface - -@property (nonatomic, readwrite, retain) NSString *apiKey; - -@end diff --git a/IRWebAPITwitPicInterface.m b/IRWebAPITwitPicInterface.m deleted file mode 100644 index 579e958..0000000 --- a/IRWebAPITwitPicInterface.m +++ /dev/null @@ -1,154 +0,0 @@ -// -// IRWebAPITwitPicInterface.m -// IRWebAPIKit -// -// Created by Evadne Wu on 1/24/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitPicInterface.h" - -#import -#import -#import - - -@interface IRWebAPITwitPicInterface () - -- (void) uploadCachedImageAtURL:(NSURL *)inCachedImageURL onProgress:(void(^)(float inProgressRatio))inProgressCallback onSuccess:(IRWebAPIInterfaceCallback)inSuccessCallback onFailure:(IRWebAPIInterfaceCallback)inFailureCallback; - -// The reason why we pile other methods here is because we want a method that cleans up after itself, so we use a cached URL. The cached image is deleted once the method call returns. - -@end - -@implementation IRWebAPITwitPicInterface - -@synthesize apiKey, authenticatingInterface; - -- (id) init { - - IRWebAPIContext *twitPicContext = [[[IRWebAPIContext alloc] initWithBaseURL:[NSURL URLWithString:@"http://api.twitpic.com/"]] autorelease]; - IRWebAPIEngine *twitPicEngine = [[[IRWebAPIEngine alloc] initWithContext:twitPicContext] autorelease]; - - twitPicEngine.parser = IRWebAPIResponseDefaultJSONParserMake(); - - self = [self initWithEngine:twitPicEngine authenticator:nil]; - - [twitPicEngine.globalRequestPreTransformers addObject:[[twitPicEngine class] defaultFormMultipartTransformer]]; - [twitPicEngine.globalResponsePostTransformers addObject:[[twitPicEngine class] defaultCleanUpTemporaryFilesResponseTransformer]]; - - if (!self) return nil; - - return self; - -} - -- (void) uploadImage:(UIImage *)inImage onProgress:(void(^)(float inProgressRatio))inProgressCallback onSuccess:(IRWebAPIInterfaceCallback)inSuccessCallback onFailure:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSData *imageDataOrNil = UIImagePNGRepresentation(inImage); - - if (!imageDataOrNil) { - - IRWebAPIKitLog(@"The incoming image can’t be turned to a PNG representation — it might be corrupted or garbled"); - - if (inFailureCallback) - inFailureCallback(nil, NO, NO); - - return; - - } - - NSURL *cachingFileURL = [[[self.engine class] newTemporaryFileURL] autorelease]; - - [imageDataOrNil writeToURL:cachingFileURL atomically:YES]; - - [self uploadCachedImageAtURL:cachingFileURL onProgress:inProgressCallback onSuccess:inSuccessCallback onFailure:inFailureCallback]; - -} - -- (void) uploadImageAtURL:(NSURL *)inImageURL onSuccess:(IRWebAPIInterfaceCallback)inSuccessCallback onFailure:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSURL *cachingFileURL = [[[self.engine class] newTemporaryFileURL] autorelease]; - - NSError *error = nil; - - if (![[NSFileManager defaultManager] copyItemAtURL:inImageURL toURL:cachingFileURL error:&error]) { - - IRWebAPIKitLog(@"Can’t copy item at %@ to %@ — aborting, calling failure handler.", inImageURL, cachingFileURL); - - if (inFailureCallback) - inFailureCallback(nil, NO, NO); - - return; - - } - - [self uploadCachedImageAtURL:cachingFileURL onProgress:nil onSuccess:inSuccessCallback onFailure:inFailureCallback]; - -} - -- (void) uploadCachedImageAtURL:(NSURL *)inCachedImageURL onProgress:(void(^)(float inProgressRatio))inProgressCallback onSuccess:(IRWebAPIInterfaceCallback)inSuccessCallback onFailure:(IRWebAPIInterfaceCallback)inFailureCallback { - - - NSAssert(self.apiKey, @"%@ needs an API key.", self); - NSAssert(self.authenticatingInterface, @"%@ needs an authenticating interface so oAuth Echo works.", self); - NSAssert([self.authenticatingInterface.authenticator isKindOfClass:[IRWebAPIXOAuthAuthenticator class]], @"Authenticator needs to be of class %@.", NSStringFromClass([IRWebAPIXOAuthAuthenticator class])); - NSAssert(self.authenticatingInterface.authenticator.currentCredentials.authenticated, @"%@ needs an authenticating interface with already authenticated credentials to work correctly.", self); - - -// Abstraction leaks at this line - NSURL *xoAuthEchoBaseURL = [NSURL URLWithString:@"1/account/verify_credentials.json" relativeToURL:self.authenticatingInterface.engine.context.baseURL]; - - [self.engine fireAPIRequestNamed:@"/2/upload.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - self.apiKey, @"key", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSMutableDictionary dictionaryWithObjectsAndKeys: - - self.apiKey, @"key", - inCachedImageURL, @"media", - @"", @"message", - - nil], kIRWebAPIEngineRequestContextFormMultipartFieldsKey, - - [NSMutableDictionary dictionaryWithObjectsAndKeys: - - [((IRWebAPIXOAuthAuthenticator *)self.authenticatingInterface.authenticator) oAuthHeaderValueForHTTPMethod:@"GET" baseURL:xoAuthEchoBaseURL arguments:nil], @"X-Verify-Credentials-Authorization", - - [xoAuthEchoBaseURL absoluteString], @"X-Auth-Service-Provider", - - nil], kIRWebAPIEngineRequestHTTPHeaderFields, - - nil] validator: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - NSHTTPURLResponse *response = (NSHTTPURLResponse *)[inResponseContext objectForKey:kIRWebAPIEngineResponseContextURLResponse]; - - if ([inResponseOrNil objectForKey:@"url"] == nil) { - - NSLog(@"Warning: No valid response (%x %@).", [response statusCode], [[response class] localizedStringForStatusCode:[response statusCode]]); - - return NO; - - } - - return YES; - - } successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - *outShouldRetry = YES; - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -@end diff --git a/IRWebAPITwitterInterface+DirectMessages.h b/IRWebAPITwitterInterface+DirectMessages.h deleted file mode 100644 index d4cc093..0000000 --- a/IRWebAPITwitterInterface+DirectMessages.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// IRWebAPITwitterInterface+DirectMessages.h -// IRWebAPIKit -// -// Created by Evadne Wu on 1/18/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" - - - - - -@interface IRWebAPITwitterInterface (DirectMessages) - -- (void) retrieveIncomingDirectMessagesWithRange:(IRWebAPITwitterDirectMessageIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveOutgoingDirectMessagesWithRange:(IRWebAPITwitterDirectMessageIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) sendDirectMessageToUser:(IRWebAPITwitterUserID)inUserID withContents:(NSString *)inContents successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) deleteDirectMessageWithID:(IRWebAPITwitterDirectMessageID)inMessageID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -@end diff --git a/IRWebAPITwitterInterface+DirectMessages.m b/IRWebAPITwitterInterface+DirectMessages.m deleted file mode 100644 index e8d8d0b..0000000 --- a/IRWebAPITwitterInterface+DirectMessages.m +++ /dev/null @@ -1,123 +0,0 @@ -// -// IRWebAPITwitterInterface+DirectMessages.m -// IRWebAPIKit -// -// Created by Evadne Wu on 1/18/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface+DirectMessages.h" - - -@implementation IRWebAPITwitterInterface (DirectMessages) - -- (void) retrieveIncomingDirectMessagesWithRange:(IRWebAPITwitterDirectMessageIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/direct_messages.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.since]), @"since_id", - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.before]), @"max_id", - [NSNumber numberWithInt:self.defaultBatchSize], @"count", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retrieveOutgoingDirectMessagesWithRange:(IRWebAPITwitterDirectMessageIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/direct_messages/sent.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.since]), @"since_id", - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.before]), @"max_id", - [NSNumber numberWithInt:self.defaultBatchSize], @"count", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) sendDirectMessageToUser:(IRWebAPITwitterUserID)inUserID withContents:(NSString *)inContents successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/direct_messages/new.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSNumber numberWithUnsignedLongLong:inUserID], @"user_id", - inContents, @"text", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) deleteDirectMessageWithID:(IRWebAPITwitterDirectMessageID)inMessageID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/direct_messages/destroy/%llu.json", inMessageID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSNumber numberWithUnsignedLongLong:inMessageID], @"id", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -@end diff --git a/IRWebAPITwitterInterface+Friendships.h b/IRWebAPITwitterInterface+Friendships.h deleted file mode 100644 index d5b5eb6..0000000 --- a/IRWebAPITwitterInterface+Friendships.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// IRWebAPITwitterInterface+Friendships.h -// IRWebAPIKit -// -// Created by Evadne Wu on 4/3/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" - -@interface IRWebAPITwitterInterface (Friendships) - -// Actually unsure whether concatenated invocation (big, single-shot) or repeated invocation works better -// So, wrote both to try them out separately - -// Note that the response is seldom written to a file in real world cases; instead it is mostly used to work other backing stores -// I believe that many callbacks + a exhaustion check might (read: can, but possibly as in quadruple-alpha) work a lot more better in this case for most use cases - -+ (BOOL) repeatedlyCalledSuccessHandlerResponseExhausted:(NSDictionary *)response; - -// returns YES if the engine agrees that the success handler is not going to be called any more in the same context - - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withConcatenatedSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -// Stitches everything in memory and return a large chunk - - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withRepeatedlyCalledSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -// Thought of integrating response, and found that way is not sustainable on mobile devices, and generally just bad -// A nil-response success callback is fired again when things are really done - - - - - -// Primitives - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withCallbackStyle:(IRWebAPIInterfaceCallbackStyle)style successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withCursor:(unsigned long long)cursorID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; // the primitive one - -@end diff --git a/IRWebAPITwitterInterface+Friendships.m b/IRWebAPITwitterInterface+Friendships.m deleted file mode 100644 index 4caf471..0000000 --- a/IRWebAPITwitterInterface+Friendships.m +++ /dev/null @@ -1,144 +0,0 @@ -// -// IRWebAPITwitterInterface+Friendships.m -// IRWebAPIKit -// -// Created by Evadne Wu on 4/3/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface+Friendships.h" - - -@implementation IRWebAPITwitterInterface (Friendships) - -+ (BOOL) repeatedlyCalledSuccessHandlerResponseExhausted:(NSDictionary *)response { - - if (!response || ![[response objectForKey:@"ids"] count]) - return YES; - - if ([[response objectForKey:@"next_cursor"] isEqual:[response objectForKey:@"previous_cursor"]]) - return YES; - - return NO; - -} - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withConcatenatedSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self retrieveFriendsOfUser:userID withCallbackStyle:IRWebAPIInterfaceCallbackStyleConcatenatedCallback successHandler:inSuccessCallback failureHandler:inFailureCallback]; - -} - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withRepeatedlyCalledSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self retrieveFriendsOfUser:userID withCallbackStyle:IRWebAPIInterfaceCallbackStyleManyCallbacks successHandler:inSuccessCallback failureHandler:inFailureCallback]; - -} - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withCallbackStyle:(IRWebAPIInterfaceCallbackStyle)style successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSMutableDictionary *actualResponseOrNil = [NSMutableDictionary dictionary]; // Get everything - - void (^enqueueIdentifiersFromResponse)(NSDictionary *response) = ^ (NSDictionary *response) { - - NSMutableArray *actualIDs = [actualResponseOrNil objectForKey:@"ids"]; - - if (![actualIDs isKindOfClass:[NSMutableArray class]]) { - - actualIDs = [[actualIDs mutableCopy] autorelease]; - [actualResponseOrNil setObject:actualIDs forKey:@"ids"]; - - } - - [actualIDs addObjectsFromArray:[response objectForKey:@"ids"]]; - - }; - - BOOL (^responseExhausted)(NSDictionary *responseBody) = ^ (NSDictionary *responseBody) { return [[self class] repeatedlyCalledSuccessHandlerResponseExhausted:responseBody]; }; - - __block void (^workingBlock)(unsigned long long queuedCursorID); - - workingBlock = ^ (unsigned long long queuedCursorID) { - - [self retrieveFriendsOfUser:userID withCursor:queuedCursorID successHandler: ^ (NSDictionary *inResponseOrNil, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - switch (style) { - - case IRWebAPIInterfaceCallbackStyleConcatenatedCallback: { - - enqueueIdentifiersFromResponse(inResponseOrNil); - - if (responseExhausted(inResponseOrNil)) { - - if (inSuccessCallback) - inSuccessCallback(actualResponseOrNil, outNotifyDelegate, outShouldRetry); - - return; - - } - - break; - - } - - case IRWebAPIInterfaceCallbackStyleManyCallbacks : { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - if (responseExhausted(inResponseOrNil)) { - - return; - - } - - break; - - } - - default: { - - NSParameterAssert(NO); - - } - - } - - workingBlock([[inResponseOrNil objectForKey:@"next_cursor"] unsignedLongLongValue]); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - NSLog(@"FAIL %@", inResponseOrNil); - - }]; - - }; - - workingBlock(-1); // -1 starts pagination, and the cursor defaults to -1 per official docs - -} - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withCursor:(unsigned long long)cursorID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/friends/ids.json"] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:cursorID]), @"cursor", - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:userID]), @"user_id", - - nil] options:nil validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -@end diff --git a/IRWebAPITwitterInterface+Geo.h b/IRWebAPITwitterInterface+Geo.h deleted file mode 100644 index b8be769..0000000 --- a/IRWebAPITwitterInterface+Geo.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// IRWebAPITwitterInterface+Geo.h -// IRWebAPIKit -// -// Created by Evadne Wu on 12/15/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" -#import - -@interface IRWebAPITwitterInterface (Geo) - -- (void) reverseGeocodeWithLocation:(CLLocation *)inLocation userinfo:(NSDictionary *)inUserInfo onSuccess:(IRWebAPICallback)inSuccessCallback onFailure:(IRWebAPICallback)inFailureCallback; - -@end diff --git a/IRWebAPITwitterInterface+Geo.m b/IRWebAPITwitterInterface+Geo.m deleted file mode 100644 index 79bab0c..0000000 --- a/IRWebAPITwitterInterface+Geo.m +++ /dev/null @@ -1,72 +0,0 @@ -// -// IRWebAPITwitterInterface+Geo.m -// IRWebAPIKit -// -// Created by Evadne Wu on 12/15/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface+Geo.h" - - - - - -@implementation IRWebAPITwitterInterface (Geo) - - - - - -- (void) reverseGeocodeWithLocation:(CLLocation *)inLocation userinfo:(NSDictionary *)inUserInfo onSuccess:(IRWebAPICallback)inSuccessCallback onFailure:(IRWebAPICallback)inFailureCallback { - - IRWebAPIContext *googleMapsContext = [[[IRWebAPIContext alloc] initWithBaseURL:[NSURL URLWithString:@"http://maps.googleapis.com/maps/api/"]] autorelease]; - IRWebAPIEngine *googleMapsEngine = [[[IRWebAPIEngine alloc] initWithContext:googleMapsContext] autorelease]; - googleMapsEngine.parser = IRWebAPIResponseDefaultJSONParserMake(); - - [googleMapsEngine fireAPIRequestNamed:@"geocode/json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSString stringWithFormat:@"%f,%f", inLocation.coordinate.latitude, inLocation.coordinate.longitude], @"latlng", - @"true", @"sensor", - - nil] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - NSLog(@"google success"); - - if (![[inResponseOrNil valueForKey:@"status"] isEqual:@"OK"]) { - - inFailureCallback(inResponseOrNil, inResponseContext, outNotifyDelegate, outShouldRetry); - return; - - } - - NSDictionary *resultArray = [inResponseOrNil valueForKey:@"results"]; - for (NSDictionary *resultObject in resultArray) { - - NSString *formattedAddress = [resultObject valueForKeyPath:@"formatted_address"]; - - if ([formattedAddress isEqual:[NSNull null]]) - continue; - - inSuccessCallback([NSDictionary dictionaryWithObject:formattedAddress forKey:@"displayString"], inResponseContext, outNotifyDelegate, outShouldRetry); - return; - - } - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - inFailureCallback(inResponseOrNil, inResponseContext, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -@end - - - - diff --git a/IRWebAPITwitterInterface+Lists.h b/IRWebAPITwitterInterface+Lists.h deleted file mode 100644 index 883f2af..0000000 --- a/IRWebAPITwitterInterface+Lists.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// IRWebAPITwitterInterface+Lists.h -// IRWebAPIKit -// -// Created by Evadne Wu on 1/17/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" - - - - - -#ifndef __IRWebAPIInterface__Lists__ -#define __IRWebAPIInterface__Lists__ - -typedef enum { - - IRWebAPITwitterListsMadeByUser, - IRWebAPITwitterListsIncludingUser, - IRWebAPITwitterListsSubscribedByUser - -} IRWebAPITwitterListsType; - -#endif - - - - - -@interface IRWebAPITwitterInterface (Lists) - -- (void) retrieveListsOfType:(IRWebAPITwitterListsType)inListType successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveStatusesFromList:(IRWebAPITwitterListID)inListID withRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -// - (void) createOrUpdateList:(IRWebAPITwitterListID)inListID withName:(NSString *)inPromisedListName becomingPrivate:(BOOL)inListBecomesPrivate successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) createListWithName:(NSString *)inName description:(NSString *)inDescription becomingPrivate:(BOOL)inListBecomesPrivate successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) updateList:(IRWebAPITwitterListID)inListID withName:(NSString *)inName description:(NSString *)inDescription becomingPrivate:(BOOL)inListBecomesPrivate successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) deleteList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - - -- (void) retrieveMembersOfList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) removeMember:(IRWebAPITwitterUserID)inUserID fromList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) addMember:(IRWebAPITwitterUserID)inUserID toList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -@end diff --git a/IRWebAPITwitterInterface+Lists.m b/IRWebAPITwitterInterface+Lists.m deleted file mode 100644 index d20aaaa..0000000 --- a/IRWebAPITwitterInterface+Lists.m +++ /dev/null @@ -1,251 +0,0 @@ -// -// IRWebAPITwitterInterface+Lists.m -// IRWebAPIKit -// -// Created by Evadne Wu on 1/17/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface+Lists.h" - - -@implementation IRWebAPITwitterInterface (Lists) - -- (void) retrieveListsOfType:(IRWebAPITwitterListsType)inListType successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/lists%@.json", self.authenticator.currentCredentials.identifier, ((^{ - - switch (inListType) { - case IRWebAPITwitterListsMadeByUser: return @""; - case IRWebAPITwitterListsIncludingUser: return @"/memberships"; - case IRWebAPITwitterListsSubscribedByUser: return @"/subscriptions"; - } - - })())] withArguments:nil options:nil validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retrieveStatusesFromList:(IRWebAPITwitterListID)inListID withRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/lists/%llu/statuses.json", self.authenticator.currentCredentials.identifier, inListID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.since]), @"since_id", - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.before]), @"max_id", - [NSNumber numberWithInt:self.defaultBatchSize], @"count", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) createListWithName:(NSString *)inName description:(NSString *)inDescription becomingPrivate:(BOOL)inListBecomesPrivate successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/lists/.json", self.authenticator.currentCredentials.identifier] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - inName, @"name", - (inListBecomesPrivate ? @"private" : @"public"), @"mode", - inDescription, @"description", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) updateList:(IRWebAPITwitterListID)inListID withName:(NSString *)inName description:(NSString *)inDescription becomingPrivate:(BOOL)inListBecomesPrivate successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/lists/%llu.json", self.authenticator.currentCredentials.identifier, inListID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - inName, @"name", - (inListBecomesPrivate ? @"private" : @"public"), @"mode", - inDescription, @"description", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) deleteList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/lists/%llu.json", self.authenticator.currentCredentials.identifier, inListID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - @"DELETE", @"_method", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retrieveMembersOfList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/%llu/members.json", self.authenticator.currentCredentials.identifier, inListID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSString stringWithFormat:@"%llu", inListID], @"id", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) removeMember:(IRWebAPITwitterUserID)inUserID fromList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/%llu/members.json", self.authenticator.currentCredentials.identifier, inListID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - @"DELETE", @"_method", - [NSString stringWithFormat:@"%llu", inUserID], @"id", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) addMember:(IRWebAPITwitterUserID)inUserID toList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/%llu/members.json", self.authenticator.currentCredentials.identifier, inListID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSString stringWithFormat:@"%llu", inUserID], @"id", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -@end \ No newline at end of file diff --git a/IRWebAPITwitterInterface+Timeline.h b/IRWebAPITwitterInterface+Timeline.h deleted file mode 100644 index aff23ee..0000000 --- a/IRWebAPITwitterInterface+Timeline.h +++ /dev/null @@ -1,56 +0,0 @@ -// -// IRWebAPITwitterInterface+Timeline.h -// IRWebAPIKit -// -// Created by Evadne Wu on 12/17/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" - - - - - -#ifndef __IRWebAPIInterface__Timeline__ -#define __IRWebAPIInterface__Timeline__ - -typedef enum { - -// IRWebAPITwitterTimelinePublic, - IRWebAPITwitterTimelineHome, - IRWebAPITwitterTimelineUser - -} IRWebAPITwitterTimelineType; - -typedef enum { - - IRWebAPITwitterRetweetByUser, // Retweets retweeted by current user - IRWebAPITwitterRetweetByFollowers, // Retweets retweeted by other people - IRWebAPITwitterRetweetOfUser // Retweets from other people, that are tweets by current user - -} IRWebAPITwitterRetweetType; - -#endif - - - - - -@interface IRWebAPITwitterInterface (Timeline) - -- (void) retrieveStatusesFromTimeline:(IRWebAPITwitterTimelineType)inTimelineType withRange:(IRWebAPITwitterStatusIDRange)range successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveMentionsWithRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveRetweetsOfType:(IRWebAPITwitterRetweetType)inType withRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveFavoritesWithRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) setStatus:(IRWebAPITwitterStatusID)inID asFavorited:(BOOL)inBecomesFavorited successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retweetStatus:(IRWebAPITwitterStatusID)inID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveStatusWithIdentifier:(IRWebAPITwitterStatusID)inID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -@end diff --git a/IRWebAPITwitterInterface+Timeline.m b/IRWebAPITwitterInterface+Timeline.m deleted file mode 100644 index 6d20112..0000000 --- a/IRWebAPITwitterInterface+Timeline.m +++ /dev/null @@ -1,231 +0,0 @@ -// -// IRWebAPITwitterInterface+Timeline.m -// IRWebAPIKit -// -// Created by Evadne Wu on 12/17/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface+Timeline.h" -#import "IRWebAPITwitterInterface+Validators.h" - -@implementation IRWebAPITwitterInterface (Timeline) - -- (void) retrieveStatusesFromTimeline:(IRWebAPITwitterTimelineType)inTimelineType withRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSString * (^methodNameForType) (IRWebAPITwitterTimelineType) = ^ NSString * (IRWebAPITwitterTimelineType inType) { - - if (inType == IRWebAPITwitterTimelineHome) - return @"1/statuses/home_timeline.json"; - - return @"1/statuses/user_timeline.json"; - - }; - - [self.engine fireAPIRequestNamed:methodNameForType(inTimelineType) withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.since]), @"since_id", - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.before]), @"max_id", - [NSNumber numberWithInt:self.defaultBatchSize], @"count", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:[self defaultTimelineValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retrieveMentionsWithRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/statuses/mentions.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.since]), @"since_id", - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.before]), @"max_id", - [NSNumber numberWithInt:self.defaultBatchSize], @"count", - [NSNumber numberWithBool:YES], @"include_rts", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:[self defaultTimelineValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retrieveRetweetsOfType:(IRWebAPITwitterRetweetType)inType withRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSString *requestName = ((^{ - - switch (inType) { - - case IRWebAPITwitterRetweetByUser: return @"1/statuses/retweeted_by_me.json"; - case IRWebAPITwitterRetweetByFollowers: return @"1/statuses/retweeted_to_me.json"; - case IRWebAPITwitterRetweetOfUser: return @"1/statuses/retweets_of_me.json"; - - } - - })()); - - if (!requestName) { - - NSLog(@"Error: %s failed because of an unknown IRWebAPITwitterRetweetType.", (char *)_cmd); - - } - - [self.engine fireAPIRequestNamed:requestName withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.since]), @"since_id", - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.before]), @"max_id", - [NSNumber numberWithInt:MIN(100, self.defaultBatchSize)], @"count", - [NSNumber numberWithBool:YES], @"include_rts", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:[self defaultTimelineValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retrieveFavoritesWithRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/favorites.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - // The range / count currently is not even supported as the API returns only the latest 20 tweets - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:[self defaultTimelineValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) setStatus:(IRWebAPITwitterStatusID)inID asFavorited:(BOOL)inBecomesFavorited successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/favorites/%@/%llu.json", (inBecomesFavorited ? @"create" : @"destroy"), inID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSNumber numberWithUnsignedLongLong:inID], @"id", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retweetStatus:(IRWebAPITwitterStatusID)inID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/statuses/retweet/%llu.json", inID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSNumber numberWithUnsignedLongLong:inID], @"id", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:[self defaultSingleTweetValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retrieveStatusWithIdentifier:(IRWebAPITwitterStatusID)inID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/statuses/show/%llu.json", inID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -@end diff --git a/IRWebAPITwitterInterface+User.h b/IRWebAPITwitterInterface+User.h deleted file mode 100644 index 4b2f131..0000000 --- a/IRWebAPITwitterInterface+User.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// IRWebAPITwitterInterface+User.h -// IRWebAPIKit -// -// Created by Evadne Wu on 4/5/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" - - -@interface IRWebAPITwitterInterface (User) - -- (void) retrieveMetadataForUserWithIdentifiers:(NSArray *)identifiers withSuccessHandler:(IRWebAPIInterfaceCallback)successBlock failureHandler:(IRWebAPIInterfaceCallback)failureBlock; - -- (void) retrieveMetadataForUser:(IRWebAPITwitterUserID)anUserID withSuccessHandler:(IRWebAPIInterfaceCallback)successBlock failureHandler:(IRWebAPIInterfaceCallback)failureBlock; - -@end diff --git a/IRWebAPITwitterInterface+User.m b/IRWebAPITwitterInterface+User.m deleted file mode 100644 index 1e917d6..0000000 --- a/IRWebAPITwitterInterface+User.m +++ /dev/null @@ -1,43 +0,0 @@ -// -// IRWebAPITwitterInterface+User.m -// IRWebAPIKit -// -// Created by Evadne Wu on 4/5/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface+User.h" - - -@implementation IRWebAPITwitterInterface (User) - -- (void) retrieveMetadataForUserWithIdentifiers:(NSArray *)identifiers withSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/users/lookup.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [identifiers componentsJoinedByString:@","], @"user_id", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -- (void) retrieveMetadataForUser:(IRWebAPITwitterUserID)anUserID withSuccessHandler:(IRWebAPIInterfaceCallback)successBlock failureHandler:(IRWebAPIInterfaceCallback)failureBlock { - - // Just a convenience! - - return [self retrieveMetadataForUserWithIdentifiers:[NSArray arrayWithObject:[NSNumber numberWithUnsignedLongLong:anUserID]] withSuccessHandler:successBlock failureHandler:failureBlock]; - -} - -@end diff --git a/IRWebAPITwitterInterface+Validators.h b/IRWebAPITwitterInterface+Validators.h deleted file mode 100644 index de36f06..0000000 --- a/IRWebAPITwitterInterface+Validators.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// IRWebAPITwitterInterface+Validators.h -// IRWebAPIKit -// -// Created by Evadne Wu on 1/17/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" - -@interface IRWebAPITwitterInterface (Validators) - -- (IRWebAPIResposeValidator) defaultNoErrorValidator; - -// Makes sure the response is 200 and does not come with an error - - -- (IRWebAPIResposeValidator) defaultValidatorForArrayNamed:(NSString *)inKeyPathToResponseArray withElementKeyPaths:(NSArray *)inKeyPaths validator:(BOOL(^)(id aKeyPath, id currentObject))inValidator; - -- (IRWebAPIResposeValidator) defaultValidatorForArrayNamed:(NSString *)inKeyPathToResponseArray withElementKeyPaths:(NSArray *)inKeyPaths; - -// Makes sure that the key path inKeyPathToResponseArray points to an NSArray, and each element in that array has values described in inKeyPaths -// The default validator is a “non-nil” validator. - - -- (IRWebAPIResposeValidator) defaultExistingValueValidatorForKeyPaths:(NSArray *)inKeyPaths; - -// return [self defaultValidatorForArrayNamed:@"response" withElementKeyPaths:inKeyPaths]; - - -- (IRWebAPIResposeValidator) defaultTimelineValidator; -- (IRWebAPIResposeValidator) defaultSingleTweetValidator; - -- (IRWebAPIResposeValidator) defaultListsValidator; - -@end diff --git a/IRWebAPITwitterInterface+Validators.m b/IRWebAPITwitterInterface+Validators.m deleted file mode 100644 index 5547aff..0000000 --- a/IRWebAPITwitterInterface+Validators.m +++ /dev/null @@ -1,125 +0,0 @@ -// -// IRWebAPITwitterInterface+Validators.m -// IRWebAPIKit -// -// Created by Evadne Wu on 1/17/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPIKit.h" - - -@implementation IRWebAPITwitterInterface (Validators) - -- (IRWebAPIResposeValidator) defaultNoErrorValidator { - - return [IRWebAPIInterface defaultNoErrorValidator]; - -} - -- (IRWebAPIResposeValidator) defaultValidatorForArrayNamed:(NSString *)inKeyPathToResponseArray withElementKeyPaths:(NSArray *)inKeyPaths validator:(BOOL(^)(id aKeyPath, id currentObject))inValidator { - - return [[(^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - if (![self defaultNoErrorValidator](inResponseOrNil, inResponseContext)) - return NO; - - NSArray *responseArray = [inResponseOrNil valueForKeyPath:inKeyPathToResponseArray]; - if (![responseArray isKindOfClass:[NSArray class]]) - return NO; - - for (id anObject in responseArray) - for (id aKeyPath in inKeyPaths) - if (!inValidator(aKeyPath, [anObject valueForKeyPath:aKeyPath])) - return NO; - - return YES; - - }) copy] autorelease]; - -} - -- (IRWebAPIResposeValidator) defaultValidatorForArrayNamed:(NSString *)inKeyPathToResponseArray withElementKeyPaths:(NSArray *)inKeyPaths { - - return [self defaultValidatorForArrayNamed:inKeyPathToResponseArray withElementKeyPaths:inKeyPaths validator: ^ (id aKeyPath, id currentObject) { - - return (BOOL)(currentObject != nil); - - }]; - -} - - -- (IRWebAPIResposeValidator) defaultExistingValueValidatorForKeyPaths:(NSArray *)inKeyPaths { - - return [self defaultValidatorForArrayNamed:@"response" withElementKeyPaths:inKeyPaths]; - -} - -- (IRWebAPIResposeValidator) defaultTimelineValidator { - - return [[(^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - if (![self defaultExistingValueValidatorForKeyPaths:[NSArray arrayWithObject:@"response"]]) - return NO; - - id response = [inResponseOrNil valueForKeyPath:@"response"]; - - if (!response || ![response isKindOfClass:[NSArray class]]) - return NO; - - if ([(NSArray *)response count] > 0) - if ([[[(NSArray *)response objectAtIndex:0] valueForKeyPath:@"text"] isEqual:[NSNull null]]) - return NO; - - return YES; - - }) copy] autorelease]; - -} - -- (IRWebAPIResposeValidator) defaultListsValidator { - - return [[(^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - if (![self defaultNoErrorValidator](inResponseOrNil, inResponseContext)) - return NO; - - id response = [inResponseOrNil valueForKeyPath:@"response"]; - - if (!response) - return NO; - - if ([response isEqual:[NSNull null]]) - return NO; - - if (![response isKindOfClass:[NSArray class]]) - return NO; - - if ([(NSArray *)response count] > 0) - if ([[[(NSArray *)response objectAtIndex:0] valueForKeyPath:@"name"] isEqual:[NSNull null]]) - return NO; - - return YES; - - }) copy] autorelease]; - -} - -- (IRWebAPIResposeValidator) defaultSingleTweetValidator { - - return [[(^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - if (![self defaultNoErrorValidator](inResponseOrNil, inResponseContext)) - return NO; - - if (![inResponseOrNil valueForKeyPath:@"text"]) - return NO; - - return YES; - - }) copy] autorelease]; - -} - -@end diff --git a/IRWebAPITwitterInterface.h b/IRWebAPITwitterInterface.h deleted file mode 100644 index c4aea62..0000000 --- a/IRWebAPITwitterInterface.h +++ /dev/null @@ -1,90 +0,0 @@ -// -// IRWebAPITwitterInterface.h -// IRWebAPIKit -// -// Created by Evadne Wu on 12/1/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPIKit.h" - -#ifndef __IRWebAPITwitterInterface__ -#define __IRWebAPITwitterInterface__ - - -typedef uint64_t IRWebAPITwitterStatusID; -#define IRWebAPITwitterStatusIdentifierNotApplicable 0 - -typedef struct IRWebAPITwitterStatusIDRange { - - IRWebAPITwitterStatusID since; - IRWebAPITwitterStatusID before; - -} IRWebAPITwitterStatusIDRange; - -#define IRWebAPITwitterStatusIDRangeNull ((IRWebAPITwitterStatusIDRange){0, 0}) - - -static inline IRWebAPITwitterStatusIDRange IRWebAPITwitterStatusIDRangeMake (IRWebAPITwitterStatusID begin, IRWebAPITwitterStatusID end) { - - IRWebAPITwitterStatusIDRange returnedRange; - - returnedRange.since = begin; - returnedRange.before = end; - - return returnedRange; - -} - -typedef uint64_t IRWebAPITwitterUserID; -typedef uint64_t IRWebAPITwitterListID; -typedef uint64_t IRWebAPITwitterDirectMessageID; - -typedef IRWebAPITwitterStatusIDRange IRWebAPITwitterDirectMessageIDRange; - -#define IRWebAPITwitterDirectMessageIDRangeNull IRWebAPITwitterStatusIDRangeNull -#define IRWebAPITwitterDirectMessageIdentifierNotApplicable IRWebAPITwitterStatusIdentifierNotApplicable - -static inline IRWebAPITwitterDirectMessageIDRange IRWebAPITwitterDirectMessageIDRangeMake (IRWebAPITwitterDirectMessageID begin, IRWebAPITwitterDirectMessageID end) { - - IRWebAPITwitterDirectMessageIDRange returnedRange; - - returnedRange.since = begin; - returnedRange.before = end; - - return returnedRange; - -} - -#endif - - - - - -@interface IRWebAPITwitterInterface : IRWebAPIInterface - -@property (nonatomic, readwrite, assign) NSUInteger defaultBatchSize; - -- (void) updateStatusForCurrentUserWithContents:(NSString *)inContents userInfo:(NSDictionary *)inUserInfo onSuccess:(IRWebAPIInterfaceCallback)inSuccessCallback onFailure:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) lookupCurrentUserWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessHandler failureHandler:(IRWebAPIInterfaceCallback)inFailureHandler; - -@end - - - - - -#import "IRWebAPITwitterInterface+Validators.h" - -#import "IRWebAPITwitterInterface+Timeline.h" -#import "IRWebAPITwitterInterface+Geo.h" -#import "IRWebAPITwitterInterface+Lists.h" -#import "IRWebAPITwitterInterface+DirectMessages.h" -#import "IRWebAPITwitterInterface+Friendships.h" -#import "IRWebAPITwitterInterface+User.h" - - - - diff --git a/IRWebAPITwitterInterface.m b/IRWebAPITwitterInterface.m deleted file mode 100644 index c57cf3d..0000000 --- a/IRWebAPITwitterInterface.m +++ /dev/null @@ -1,173 +0,0 @@ -// -// IRWebAPITwitterInterface.m -// IRWebAPIKit -// -// Created by Evadne Wu on 12/1/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" - -@implementation IRWebAPITwitterInterface - -@synthesize defaultBatchSize; -@synthesize consumerKey, consumerSecret; -@dynamic authenticator; - -- (id) init { - - IRWebAPIContext *twitterContext = [[[IRWebAPIContext alloc] initWithBaseURL:[NSURL URLWithString:@"https://api.twitter.com/"]] autorelease]; - - IRWebAPIEngine *twitterEngine = [[[IRWebAPIEngine alloc] initWithContext:twitterContext] autorelease]; - - twitterEngine.parser = IRWebAPIResponseDefaultJSONParserMake(); - - IRWebAPIXOAuthAuthenticator *twitterAuthenticator = [[[IRWebAPIXOAuthAuthenticator alloc] initWithEngine:twitterEngine] autorelease]; - - self = [self initWithEngine:twitterEngine authenticator:twitterAuthenticator]; - - if (!self) return nil; - - self.defaultBatchSize = 200; - - return self; - -} - -- (void) dealloc { - -// IRWebAPIInterfaceXOAuthAuthenticating - self.consumerKey = nil; - self.consumerSecret = nil; - - [super dealloc]; - -} - - - - - -- (void) setConsumerKey:(NSString *)inConsumerKey { - - ((IRWebAPIXOAuthAuthenticator *)(self.authenticator)).consumerKey = inConsumerKey; - -} - -- (NSString *) consumerKey { - - return ((IRWebAPIXOAuthAuthenticator *)(self.authenticator)).consumerKey; - -} - -- (void) setConsumerSecret:(NSString *)inConsumerSecret { - - ((IRWebAPIXOAuthAuthenticator *)(self.authenticator)).consumerSecret = inConsumerSecret; - -} - -- (NSString *) consumerSecret { - - return ((IRWebAPIXOAuthAuthenticator *)(self.authenticator)).consumerSecret; - -} - -- (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess:(IRWebAPIAuthenticatorCallback)successHandler onFailure:(IRWebAPIAuthenticatorCallback)failureHandler { - - NSLog(@"%@ %s", self, __PRETTY_FUNCTION__); - - NSLog(@"My authenticator , %@", self.authenticator); - - [self.authenticator authenticateCredentials:inCredentials onSuccess: ^ (IRWebAPIAuthenticator *inAuthenticator, BOOL isAuthenticated, BOOL *inShouldRetry) { - - NSLog(@"authentication is done."); - - if (!isAuthenticated) { - - *inShouldRetry = YES; - return; - - } - - if (successHandler) - successHandler(inAuthenticator, isAuthenticated, inShouldRetry); - - } onFailure: ^ (IRWebAPIAuthenticator *inAuthenticator, BOOL isAuthenticated, BOOL *inShouldRetry) { - - NSLog(@"Failed. %@", self); - - if (failureHandler) - failureHandler(inAuthenticator, isAuthenticated, inShouldRetry); - - }]; - -} - - - - - -- (void) updateStatusForCurrentUserWithContents:(NSString *)inContents userInfo:(NSDictionary *)inUserInfo onSuccess:(IRWebAPIInterfaceCallback)inSuccessCallback onFailure:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/statuses/update.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - inContents, @"status", - [NSString stringWithFormat:@"%llu", [(NSNumber *)[inUserInfo objectForKey:@"replyingStatusIdentifier"] unsignedLongLongValue]], @"in_reply_to_status_id", - [inUserInfo objectForKey:@"latitude"], @"lat", - [inUserInfo objectForKey:@"longitude"], @"lng", - [inUserInfo objectForKey:@"placeIdentifier"], @"placeID", - [inUserInfo objectForKey:@"displaysCoordinates"], @"display_coordinates", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - id returnedError = [inResponseOrNil objectForKey:@"error"]; - return (BOOL)(returnedError == nil); - - } successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - NSLog(@"statuses/update response: %@", inResponseOrNil); - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - NSLog(@"Failed. %@", inResponseOrNil); - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) lookupCurrentUserWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/account/verify_credentials.json" withArguments:nil options:nil validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -@end diff --git a/IRWebAPIXOAuthAuthenticator.m b/IRWebAPIXOAuthAuthenticator.m index dac7e7a..51cbba4 100644 --- a/IRWebAPIXOAuthAuthenticator.m +++ b/IRWebAPIXOAuthAuthenticator.m @@ -22,35 +22,10 @@ @implementation IRWebAPIXOAuthAuthenticator @synthesize consumerKey, consumerSecret, retrievedToken, retrievedTokenSecret; @synthesize currentCredentials; -- (id) initWithEngine:(IRWebAPIEngine *)inEngine { - - self = [super initWithEngine:inEngine]; if (!self) return nil; - - consumerKey = nil; - consumerSecret = nil; - retrievedToken = nil; - retrievedTokenSecret = nil; - - xAuthAccessTokenBaseURL = nil; - authorizeURL = nil; - - return self; - -} - -- (void) dealloc { - - self.consumerKey = nil; - self.consumerSecret = nil; - self.retrievedToken = nil; - self.retrievedTokenSecret = nil; - - [super dealloc]; - -} - - (void) createTransformerBlocks { + __weak IRWebAPIXOAuthAuthenticator *wSelf = self; + self.globalRequestPostTransformerBlock = ^ (NSDictionary *inOriginalContext) { NSMutableDictionary *mutatedContext = [inOriginalContext mutableCopy]; @@ -82,14 +57,12 @@ - (void) createTransformerBlocks { } - [mutatedContextHeaderFields setObject:[self oAuthHeaderValueForRequestContext:mutatedContext] forKey:@"Authorization"]; + [mutatedContextHeaderFields setObject:[wSelf oAuthHeaderValueForRequestContext:mutatedContext] forKey:@"Authorization"]; if (removesQueryParameters) [mutatedContext setObject:[NSMutableArray array] forKey:kIRWebAPIEngineRequestHTTPQueryParameters]; - IRWebAPIKitLog(@"mutatedContext %@", mutatedContext); - - return [mutatedContext autorelease]; + return mutatedContext; }; @@ -167,8 +140,6 @@ - (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess: - (NSDictionary *) oAuthHeaderValuesForHTTPMethod:(NSString *)inHTTPMethod baseURL:(NSURL *)inBaseURL arguments:(NSDictionary *)inMethodArguments { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSMutableDictionary *signatureStringParameters = [NSMutableDictionary dictionary]; NSMutableDictionary *oAuthParameters = [NSMutableDictionary dictionaryWithObjectsAndKeys: @@ -207,12 +178,7 @@ - (NSDictionary *) oAuthHeaderValuesForHTTPMethod:(NSString *)inHTTPMethod baseU ) forKey:@"oauth_signature"]; - [oAuthParameters retain]; - [pool drain]; - - IRWebAPIKitLog(@"oAuthHeaderValuesForHTTPMethod -> %@", oAuthParameters); - - return [oAuthParameters autorelease]; + return oAuthParameters; } From 23ff1adac78c82f4fe1789efd5a8b8b4d5326c76 Mon Sep 17 00:00:00 2001 From: Evadne Wu Date: Tue, 26 Jun 2012 14:40:35 +0800 Subject: [PATCH 08/32] WIP - adds NSURLConnection delegate method interceptor - uses request context and cleans up interface - fixes up categories on the request context for form URL encoding and multipart data generation - initial options transforming kludge in anticipation of late evaluation vanquishing entire hack --- IRRemoteResourcesManager.m | 28 +- IRWebAPIEngine+ExternalTransforms.m | 50 +-- IRWebAPIEngine+FormMultipart.h | 10 +- IRWebAPIEngine+FormMultipart.m | 106 +++-- IRWebAPIEngine+FormURLEncoding.h | 10 +- IRWebAPIEngine+FormURLEncoding.m | 84 ++-- IRWebAPIEngine+LocalCaching.h | 8 +- IRWebAPIEngine+LocalCaching.m | 74 ++-- IRWebAPIEngine+OperationFiring.h | 27 ++ IRWebAPIEngine+OperationFiring.m | 69 ++++ IRWebAPIEngine.h | 40 +- IRWebAPIEngine.m | 542 +++----------------------- IRWebAPIHelpers.m | 4 +- IRWebAPIInterceptor.h | 15 + IRWebAPIInterceptor.m | 32 ++ IRWebAPIInterface+Validators.h | 2 +- IRWebAPIInterface+Validators.m | 8 +- IRWebAPIKit.h | 9 +- IRWebAPIKit.xcodeproj/project.pbxproj | 34 ++ IRWebAPIKitDefines.h | 131 +------ IRWebAPIKitDefines.m | 14 - IRWebAPIRequestContext.h | 38 ++ IRWebAPIRequestContext.m | 142 +++++++ IRWebAPIRequestOperation.h | 32 ++ IRWebAPIRequestOperation.m | 217 +++++++++++ IRWebAPIXOAuthAuthenticator.h | 36 +- IRWebAPIXOAuthAuthenticator.m | 91 +++-- 27 files changed, 990 insertions(+), 863 deletions(-) create mode 100644 IRWebAPIEngine+OperationFiring.h create mode 100644 IRWebAPIEngine+OperationFiring.m create mode 100644 IRWebAPIInterceptor.h create mode 100644 IRWebAPIInterceptor.m create mode 100644 IRWebAPIRequestContext.h create mode 100644 IRWebAPIRequestContext.m create mode 100644 IRWebAPIRequestOperation.h create mode 100644 IRWebAPIRequestOperation.m diff --git a/IRRemoteResourcesManager.m b/IRRemoteResourcesManager.m index 3b0fa0b..92dc3f4 100644 --- a/IRRemoteResourcesManager.m +++ b/IRRemoteResourcesManager.m @@ -380,32 +380,36 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri } - __block __typeof__(self) nrSelf = self; + __weak IRRemoteResourcesManager *wSelf = self; - [nrSelf performInBackground: ^ { + [wSelf performInBackground: ^ { - __block IRRemoteResourceDownloadOperation *operation = [self operationWithURL:anURL]; + IRRemoteResourceDownloadOperation *operation = [wSelf operationWithURL:anURL]; if (!operation) { - operation = [self prospectiveOperationForURL:anURL enqueue:YES]; + operation = [wSelf prospectiveOperationForURL:anURL enqueue:YES]; operation.queuePriority = priority; - [nrSelf addOperation:operation]; + __weak IRRemoteResourceDownloadOperation *wOperation = operation; + + [wSelf addOperation:operation]; [operation appendCompletionBlock:^{ - [nrSelf removeOperation:operation]; + [wSelf removeOperation:wOperation]; }]; } else { - if (forcesReload && [nrSelf.queue.operations containsObject:operation]) { + if (forcesReload && [wSelf.queue.operations containsObject:operation]) { operation = [operation continuationOperationCancellingCurrentOperation:YES]; operation.queuePriority = priority; - [nrSelf addOperation:operation]; + __weak IRRemoteResourceDownloadOperation *wOperation = operation; + + [wSelf addOperation:operation]; [operation appendCompletionBlock:^{ - [nrSelf removeOperation:operation]; + [wSelf removeOperation:wOperation]; }]; } @@ -420,7 +424,7 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri if (![[NSFileManager defaultManager] fileExistsAtPath:capturedPath]) { - [nrSelf performInBackground:^{ + [wSelf performInBackground:^{ aBlock(nil); }]; @@ -428,7 +432,7 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri } - [nrSelf performInBackground: ^ { + [wSelf performInBackground: ^ { NSCParameterAssert([[NSFileManager defaultManager] fileExistsAtPath:capturedPath]); aBlock([NSURL fileURLWithPath:capturedPath]); @@ -443,7 +447,7 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri [self beginSuspendingOperationQueue]; - [nrSelf performInBackground: ^ { + [wSelf performInBackground: ^ { [self enqueueOperationsIfNeeded]; diff --git a/IRWebAPIEngine+ExternalTransforms.m b/IRWebAPIEngine+ExternalTransforms.m index e11329e..3535097 100644 --- a/IRWebAPIEngine+ExternalTransforms.m +++ b/IRWebAPIEngine+ExternalTransforms.m @@ -7,14 +7,16 @@ // #import "IRWebAPIEngine+ExternalTransforms.h" +#import "IRWebAPIRequestContext.h" +#import "IRWebAPIHelpers.h" @interface IRWebAPIEngine (ExternalTransforms_KnownPrivate) -- (NSDictionary *) baseRequestContextWithMethodName:(NSString *)inMethodName arguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil; +- (IRWebAPIRequestContext *) baseRequestContextWithMethodName:(NSString *)inMethodName arguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil; -- (NSDictionary *) requestContextByTransformingContext:(NSDictionary *)inContext forMethodNamed:(NSString *)inMethodName; +- (IRWebAPIRequestContext *) requestContextByTransformingContext:(IRWebAPIRequestContext *)inContext forMethodNamed:(NSString *)inMethodName; -- (NSURLRequest *) requestWithContext:(NSDictionary *)inContext; +- (NSURLRequest *) requestWithContext:(IRWebAPIRequestContext *)inContext; @end @@ -22,14 +24,14 @@ @implementation IRWebAPIEngine (ExternalTransforms) - (NSURLRequest *) transformedRequestWithRequest:(NSURLRequest *)aRequest usingMethodName:(NSString *)aName { - NSDictionary *baseContext = [self baseRequestContextWithMethodName:aName arguments:nil options:nil]; + IRWebAPIRequestContext *baseContext = [self baseRequestContextWithMethodName:aName arguments:nil options:nil]; - NSURL *baseURL = [baseContext objectForKey:kIRWebAPIEngineRequestHTTPBaseURL]; - NSDictionary *headerFields = [baseContext objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - NSDictionary *arguments = [baseContext objectForKey:kIRWebAPIEngineRequestHTTPQueryParameters]; - NSData *httpBody = [baseContext objectForKey:kIRWebAPIEngineRequestHTTPBody]; - NSString *httpMethod = [baseContext objectForKey:kIRWebAPIEngineRequestHTTPMethod]; - IRWebAPIResponseParser responseParser = [baseContext objectForKey:kIRWebAPIEngineParser]; + NSURL *baseURL = baseContext.baseURL; + NSDictionary *headerFields = baseContext.headerFields; + NSDictionary *arguments = baseContext.queryParams; + NSData *httpBody = baseContext.body; + NSString *httpMethod = baseContext.method; + IRWebAPIResponseParser responseParser = baseContext.parser; if ([[aRequest allHTTPHeaderFields] count]) headerFields = [aRequest allHTTPHeaderFields]; @@ -59,22 +61,20 @@ - (NSURLRequest *) transformedRequestWithRequest:(NSURLRequest *)aRequest usingM } - NSDictionary *inferredContext = [NSDictionary dictionaryWithObjectsAndKeys: + IRWebAPIRequestContext *inferredContext = [IRWebAPIRequestContext new]; + inferredContext.baseURL = baseURL; + [headerFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [inferredContext setValue:obj forHeaderField:key]; + }]; + [arguments enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [inferredContext setValue:obj forQueryParam:key]; + }]; + inferredContext.body = httpBody; + inferredContext.method = httpMethod; + inferredContext.parser = responseParser; - baseURL, kIRWebAPIEngineRequestHTTPBaseURL, - headerFields, kIRWebAPIEngineRequestHTTPHeaderFields, - arguments, kIRWebAPIEngineRequestHTTPQueryParameters, - httpBody, kIRWebAPIEngineRequestHTTPBody, - httpMethod, kIRWebAPIEngineRequestHTTPMethod, - responseParser, kIRWebAPIEngineParser, - aName, kIRWebAPIEngineIncomingMethodName, - - nil]; - - NSDictionary *transformedContext = [self requestContextByTransformingContext:inferredContext forMethodNamed:aName]; - NSURLRequest *returnedRequest = [self requestWithContext:transformedContext]; - - return returnedRequest; + IRWebAPIRequestContext *transformedContext = [self requestContextByTransformingContext:inferredContext forMethodNamed:aName]; + return [[IRWebAPIRequestOperation alloc] initWithContext:transformedContext].request; } diff --git a/IRWebAPIEngine+FormMultipart.h b/IRWebAPIEngine+FormMultipart.h index 9aead71..d6857c7 100644 --- a/IRWebAPIEngine+FormMultipart.h +++ b/IRWebAPIEngine+FormMultipart.h @@ -7,12 +7,20 @@ // #import "IRWebAPIEngine.h" +#import "IRWebAPIRequestContext.h" +@interface IRWebAPIRequestContext (FormMultipart) -extern NSString * const kIRWebAPIEngineRequestContextFormMultipartFieldsKey; +@property (nonatomic, readonly, copy) NSDictionary *formMultipartFields; +- (void) removeAllFormMultipartFieldValues; +- (void) setValue:(id)obj forFormMultipartField:(NSString *)key; + +@end @interface IRWebAPIEngine (FormMultipart) + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer; @end + +extern NSString * const kIRWebAPIEngineRequestContextFormMultipartFieldsKey; diff --git a/IRWebAPIEngine+FormMultipart.m b/IRWebAPIEngine+FormMultipart.m index 389ffeb..fb01a5a 100644 --- a/IRWebAPIEngine+FormMultipart.m +++ b/IRWebAPIEngine+FormMultipart.m @@ -6,57 +6,90 @@ // Copyright 2011 Iridia Productions. All rights reserved. // +#import #import "IRWebAPIEngine+FormMultipart.h" - #import "IRWebAPIEngine+LocalCaching.h" +#import "IRWebAPIHelpers.h" NSString * const kIRWebAPIEngineRequestContextFormMultipartFieldsKey = @"kIRWebAPIEngineRequestContextFormMultipartFieldsKey"; +static NSString * const kFormMultipartFields = @"-[IRWebAPIRequestContext(FormMultipart) formMultipartFields]"; + +@implementation IRWebAPIRequestContext (FormMultipart) + +- (NSDictionary *) formMultipartFields { + + NSMutableDictionary *formMultipartFields = objc_getAssociatedObject(self, &kFormMultipartFields); + + if (!formMultipartFields) { + formMultipartFields = [NSMutableDictionary dictionary]; + objc_setAssociatedObject(self, &kFormMultipartFields, formMultipartFields, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + + return [formMultipartFields copy]; + +} + +- (void) removeAllFormMultipartFieldValues { + + [self willChangeValueForKey:@"formMultipartFields"]; + objc_setAssociatedObject(self, &kFormMultipartFields, nil, OBJC_ASSOCIATION_ASSIGN); + [self didChangeValueForKey:@"formMultipartFields"]; + +} + +- (void) setValue:(id)obj forFormMultipartField:(NSString *)key { + + NSMutableDictionary *formMultipartFields = objc_getAssociatedObject(self, &kFormMultipartFields); + + if (!formMultipartFields) { + formMultipartFields = [NSMutableDictionary dictionary]; + objc_setAssociatedObject(self, &kFormMultipartFields, formMultipartFields, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + + [self willChangeValueForKey:@"formMultipartFields"]; + + if (obj) { + [formMultipartFields setObject:obj forKey:key]; + } else { + [formMultipartFields removeObjectForKey:key]; + } + + [self didChangeValueForKey:@"formMultipartFields"]; + +} + +@end + @implementation IRWebAPIEngine (FormMultipart) + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { - return [(^ (NSDictionary *inOriginalContext) { + return [(^ (IRWebAPIRequestContext *context) { - NSDictionary *formNamesToContents = [inOriginalContext objectForKey:kIRWebAPIEngineRequestContextFormMultipartFieldsKey]; - - if(!formNamesToContents || ([formNamesToContents count] == 0)) - return inOriginalContext; + NSDictionary *formNamesToContents = context.formMultipartFields; - NSMutableDictionary *returnedContext = [inOriginalContext mutableCopy]; + if (![formNamesToContents count]) + return context; NSError *error; NSURL *fileHandleURL = [[self class] newTemporaryFileURL]; if (![[NSFileManager defaultManager] createFileAtPath:[fileHandleURL path] contents:[NSData data] attributes:nil]) { - NSLog(@"Error creating file for URL %@.", fileHandleURL); - return (NSDictionary *)returnedContext; - + return context; } NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingToURL:fileHandleURL error:&error]; if (!fileHandle) { - NSLog(@"Error grabbing file handle for URL %@: %@", fileHandleURL, error); - return (NSDictionary *)returnedContext; - + return context; } [fileHandle truncateFileAtOffset:0]; [fileHandle seekToEndOfFile]; - - NSMutableDictionary *headerFields = [returnedContext objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - if (!headerFields) { - - headerFields = [NSMutableDictionary dictionary]; - [returnedContext setObject:headerFields forKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - - } - - [headerFields setObject:@"8bit" forKey:@"Content-Transfer-Encoding"]; - + [context setValue:@"8bit" forHeaderField:@"Content-Transfer-Encoding"]; NSString *mineBoundary = [NSString stringWithFormat:@"----_=_%@_%@_%@_=_----", @@ -70,7 +103,8 @@ + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { NSData *newLineData = [@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]; NSData *separatorData = [@"--" dataUsingEncoding:NSUTF8StringEncoding]; - [headerFields setObject:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", mineBoundary] forKey:@"Content-Type"]; + NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", mineBoundary]; + [context setValue:contentType forHeaderField:@"Content-Type"]; // Start writing @@ -148,24 +182,12 @@ + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { [fileHandle closeFile]; - [returnedContext setObject:[NSData dataWithContentsOfMappedFile:[fileHandleURL path]] forKey:kIRWebAPIEngineRequestHTTPBody]; - - - NSMutableArray *temporaryFileURLs = [returnedContext objectForKey:kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey]; - if (!temporaryFileURLs) { - - temporaryFileURLs = [NSMutableArray array]; - [returnedContext setObject:temporaryFileURLs forKey:kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey]; - - } - - [temporaryFileURLs addObject:fileHandleURL]; - - [returnedContext setObject:temporaryFileURLs forKey:kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey]; - [returnedContext removeObjectForKey:kIRWebAPIEngineRequestContextFormMultipartFieldsKey]; - [returnedContext setObject:@"POST" forKey:kIRWebAPIEngineRequestHTTPMethod]; + [context setBody:[NSData dataWithContentsOfMappedFile:[fileHandleURL path]]]; + [context addCacheFileURL:fileHandleURL]; + [context removeAllFormMultipartFieldValues]; + [context setMethod:@"POST"]; - return (NSDictionary *)returnedContext; + return context; }) copy]; diff --git a/IRWebAPIEngine+FormURLEncoding.h b/IRWebAPIEngine+FormURLEncoding.h index ce9a911..1b108e1 100644 --- a/IRWebAPIEngine+FormURLEncoding.h +++ b/IRWebAPIEngine+FormURLEncoding.h @@ -8,12 +8,18 @@ #import "IRWebAPIEngine.h" -extern NSString * const kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey; +@interface IRWebAPIRequestContext (FormURLEncoding) -NSData * IRWebAPIEngineFormURLEncodedDataWithDictionary (NSDictionary *dictionary); +@property (nonatomic, readonly, copy) NSDictionary *formURLEncodingFields; +- (void) removeAllFormURLEncodingFieldValues; +- (void) setValue:(id)obj forFormURLEncodingField:(NSString *)key; + +@end @interface IRWebAPIEngine (FormURLEncoding) + (IRWebAPIRequestContextTransformer) defaultFormURLEncodingTransformer; @end + +extern NSData * IRWebAPIEngineFormURLEncodedDataWithDictionary (NSDictionary *formNamesToContents); diff --git a/IRWebAPIEngine+FormURLEncoding.m b/IRWebAPIEngine+FormURLEncoding.m index 804bba7..a48f379 100644 --- a/IRWebAPIEngine+FormURLEncoding.m +++ b/IRWebAPIEngine+FormURLEncoding.m @@ -9,39 +9,77 @@ #import "IRWebAPIHelpers.h" #import "IRWebAPIEngine+FormURLEncoding.h" -NSString * const kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey = @"IRWebAPIEngineRequestContextFormURLEncodingFields"; +extern NSData * IRWebAPIEngineFormURLEncodedDataWithDictionary (NSDictionary *dictionary); + +static NSString * const kFormURLEncodingFields = @"-[IRWebAPIRequestContext(FormURLEncoding) formURLEncodingFields]"; + +@implementation IRWebAPIRequestContext (FormURLEncoding) + +- (NSDictionary *) formURLEncodingFields { + + NSMutableDictionary *formURLEncodingFields = objc_getAssociatedObject(self, &kFormURLEncodingFields); + + if (!formURLEncodingFields) { + formURLEncodingFields = [NSMutableDictionary dictionary]; + objc_setAssociatedObject(self, &kFormURLEncodingFields, formURLEncodingFields, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + + return [formURLEncodingFields copy]; + +} + +- (void) removeAllFormURLEncodingFieldValues { + + [self willChangeValueForKey:@"formURLEncodingFields"]; + objc_setAssociatedObject(self, &kFormURLEncodingFields, nil, OBJC_ASSOCIATION_ASSIGN); + [self didChangeValueForKey:@"formURLEncodingFields"]; + +} + +- (void) setValue:(id)obj forFormURLEncodingField:(NSString *)key { + + NSMutableDictionary *formURLEncodingFields = objc_getAssociatedObject(self, &kFormURLEncodingFields); + + if (!formURLEncodingFields) { + formURLEncodingFields = [NSMutableDictionary dictionary]; + objc_setAssociatedObject(self, &kFormURLEncodingFields, formURLEncodingFields, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + + [self willChangeValueForKey:@"formURLEncodingFields"]; + + if (obj) { + [formURLEncodingFields setObject:obj forKey:key]; + } else { + [formURLEncodingFields removeObjectForKey:key]; + } + + [self didChangeValueForKey:@"formURLEncodingFields"]; + +} + +@end + @implementation IRWebAPIEngine (FormURLEncoding) + (IRWebAPIRequestContextTransformer) defaultFormURLEncodingTransformer { - return [(^ (NSDictionary *inOriginalContext) { + return [(^ (IRWebAPIRequestContext *context) { - NSDictionary *formNamesToContents = [inOriginalContext objectForKey:kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey]; - - if (![formNamesToContents count]) - return inOriginalContext; - - NSMutableDictionary *returnedContext = [inOriginalContext mutableCopy]; - NSMutableDictionary *headerFields = [returnedContext objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - - if (!headerFields) { - headerFields = [NSMutableDictionary dictionary]; - [returnedContext setObject:headerFields forKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - } - - [headerFields setObject:@"8bit" forKey:@"Content-Transfer-Encoding"]; - [headerFields setObject:@"application/x-www-form-urlencoded" forKey:@"Content-Type"]; - - NSData *sentData = IRWebAPIEngineFormURLEncodedDataWithDictionary(formNamesToContents); + NSDictionary *formURLEncodingFields = context.formURLEncodingFields; + + if (![formURLEncodingFields count]) + return context; - [returnedContext setObject:sentData forKey:kIRWebAPIEngineRequestHTTPBody]; + [context setValue:@"8bit" forHeaderField:@"Content-Transfer-Encoding"]; + [context setValue:@"application/x-www-form-urlencoded" forHeaderField:@"Content-Type"]; - [returnedContext removeObjectForKey:kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey]; + [context setBody:IRWebAPIEngineFormURLEncodedDataWithDictionary(formURLEncodingFields)]; + [context removeAllFormURLEncodingFieldValues]; - [returnedContext setObject:@"POST" forKey:kIRWebAPIEngineRequestHTTPMethod]; + [context setMethod:@"POST"]; - return (NSDictionary *)returnedContext; + return context; }) copy]; diff --git a/IRWebAPIEngine+LocalCaching.h b/IRWebAPIEngine+LocalCaching.h index 1c0f04c..7c9b7ad 100644 --- a/IRWebAPIEngine+LocalCaching.h +++ b/IRWebAPIEngine+LocalCaching.h @@ -7,11 +7,15 @@ // #import "IRWebAPIEngine.h" +#import "IRWebAPIRequestContext.h" -#import +@interface IRWebAPIRequestContext (LocalCaching) +@property (nonatomic, readonly, copy) NSArray *cacheFileURLs; +- (void) removeAllCacheFileURLValues; +- (void) addCacheFileURL:(NSURL *)obj; -extern NSString * const kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey; +@end @interface IRWebAPIEngine (LocalCaching) diff --git a/IRWebAPIEngine+LocalCaching.m b/IRWebAPIEngine+LocalCaching.m index dbae292..9dc8b4d 100644 --- a/IRWebAPIEngine+LocalCaching.m +++ b/IRWebAPIEngine+LocalCaching.m @@ -11,12 +11,46 @@ #import "IRWebAPIEngine+LocalCaching.h" #import "IRWebAPIHelpers.h" +static NSString * const kCacheFileURLS = @"-[IRWebAPIRequestContext(LocalCaching) cacheFileURLs]"; -NSString * const kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey = @"kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey"; -NSString * const kIRWebAPIEngineLocallocalCacheDirectoryPath = @"kIRWebAPIEngineLocalCachingBasePath"; +@implementation IRWebAPIRequestContext (LocalCaching) +- (NSArray *) cacheFileURLs { + return [objc_getAssociatedObject(self, &kCacheFileURLS) copy]; +} + +- (void) removeAllCacheFileURLValues { + + [self willChangeValueForKey:@"cacheFileURLs"]; + objc_setAssociatedObject(self, &kCacheFileURLS, nil, OBJC_ASSOCIATION_ASSIGN); + [self didChangeValueForKey:@"cacheFileURLs"]; + +} + +- (void) addCacheFileURL:(NSURL *)obj { + + NSMutableArray *cacheFileURLs = objc_getAssociatedObject(self, &kCacheFileURLS); + + if (!cacheFileURLs) { + cacheFileURLs = [NSMutableArray array]; + objc_setAssociatedObject(self, &cacheFileURLs, cacheFileURLs, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + + [self willChangeValueForKey:@"cacheFileURLs"]; + + if (obj) { + [cacheFileURLs addObject:obj]; + } else { + [cacheFileURLs removeObject:obj]; + } + + [self didChangeValueForKey:@"cacheFileURLs"]; + +} + +@end @implementation IRWebAPIEngine (LocalCaching) @@ -26,51 +60,31 @@ + (NSURL *) newTemporaryFileURL { NSString *applicationCacheDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]; NSString *preferredCacheDirectoryPath = [applicationCacheDirectory stringByAppendingPathComponent:NSStringFromClass([self class])]; - NSError *error; - if (![[NSFileManager defaultManager] createDirectoryAtPath:preferredCacheDirectoryPath withIntermediateDirectories:YES attributes:nil error:&error]) { + if ([[NSFileManager defaultManager] createDirectoryAtPath:preferredCacheDirectoryPath withIntermediateDirectories:YES attributes:nil error:nil]) + return [NSURL fileURLWithPath:[preferredCacheDirectoryPath stringByAppendingPathComponent:IRWebAPIKitNonce()]]; - NSLog(@"Erorr occurred while assuring cache directory existence: %@", error); - return nil; - - }; - - return [NSURL fileURLWithPath:[preferredCacheDirectoryPath stringByAppendingPathComponent:IRWebAPIKitNonce()]]; + return nil; } + (BOOL) cleanUpTemporaryFileAtURL:(NSURL *)inTemporaryFileURL { - NSError *error; - - if (![[NSFileManager defaultManager] removeItemAtURL:inTemporaryFileURL error:&error]) { - - NSLog(@"Error removing file at URL %@: %@", inTemporaryFileURL, error); - return NO; - - } else { - - NSLog(@"Removed %@", inTemporaryFileURL); - - } - - return YES; + return [[NSFileManager defaultManager] removeItemAtURL:inTemporaryFileURL error:nil]; } + (IRWebAPIResponseContextTransformer) defaultCleanUpTemporaryFilesResponseTransformer { - return [(^ (NSDictionary *inParsedResponse, NSDictionary *inResponseContext) { + return [(^ (NSDictionary *inParsedResponse, IRWebAPIRequestContext *inResponseContext) { - NSArray *cachedFileURLs = [[inResponseContext objectForKey:kIRWebAPIEngineResponseContextOriginalRequestContext] objectForKey:kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey]; + NSArray *cachedFileURLs = inResponseContext.cacheFileURLs; - // DISPATCH_QUEUE_PRIORITY_BACKGROUND is unrecognized by LLVM 2.0 so we’re using the number it uses - dispatch_async(dispatch_get_global_queue(-2, 0), ^ { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^ { - if (cachedFileURLs) for (NSURL *aFileURL in cachedFileURLs) - [self cleanUpTemporaryFileAtURL:aFileURL]; + [self cleanUpTemporaryFileAtURL:aFileURL]; }); diff --git a/IRWebAPIEngine+OperationFiring.h b/IRWebAPIEngine+OperationFiring.h new file mode 100644 index 0000000..5e5c493 --- /dev/null +++ b/IRWebAPIEngine+OperationFiring.h @@ -0,0 +1,27 @@ +// +// IRWebAPIEngine+OperationFiring.h +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import "IRWebAPIEngine.h" + +@interface IRWebAPIEngine (OperationFiring) + +- (void) fireAPIRequestNamed:(NSString *)methodName withArguments:(NSDictionary *)arguments options:(NSDictionary *)options validator:(IRWebAPIResponseValidator)validatorBlock successHandler:(IRWebAPICallback)successBlock failureHandler:(IRWebAPICallback)failureBlock; + +@end + +extern NSString * const kIRWebAPIEngineRequestHTTPBaseURL; +extern NSString * const kIRWebAPIEngineRequestHTTPHeaderFields; +extern NSString * const kIRWebAPIEngineRequestHTTPPOSTParameters; +extern NSString * const kIRWebAPIEngineRequestHTTPBody; +extern NSString * const kIRWebAPIEngineRequestHTTPQueryParameters; +extern NSString * const kIRWebAPIEngineRequestHTTPMethod; +extern NSString * const kIRWebAPIEngineParser; +extern NSString * const kIRWebAPIEngineResponseContextURLResponse; +extern NSString * const kIRWebAPIRequestTimeout; + +extern NSString * const kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey; diff --git a/IRWebAPIEngine+OperationFiring.m b/IRWebAPIEngine+OperationFiring.m new file mode 100644 index 0000000..93b50f6 --- /dev/null +++ b/IRWebAPIEngine+OperationFiring.m @@ -0,0 +1,69 @@ +// +// IRWebAPIEngine+OperationFiring.m +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import "IRWebAPIEngine+OperationFiring.h" +#import "IRWebAPIRequestContext.h" +#import "IRWebAPIEngine+FormURLEncoding.h" +#import "IRWebAPIRequestOperation.h" +#import "IRWebAPIEngine+FormMultipart.h" + +NSString * const kIRWebAPIEngineRequestHTTPBaseURL = @"kIRWebAPIEngineRequestHTTPBaseURL"; +NSString * const kIRWebAPIEngineRequestHTTPHeaderFields = @"kIRWebAPIEngineRequestHTTPHeaderFields"; +NSString * const kIRWebAPIEngineRequestHTTPPOSTParameters = @"kIRWebAPIEngineRequestHTTPPOSTParameters"; +NSString * const kIRWebAPIEngineRequestHTTPBody = @"kIRWebAPIEngineRequestHTTPBody"; +NSString * const kIRWebAPIEngineRequestHTTPQueryParameters = @"kIRWebAPIEngineRequestHTTPQueryParameters"; +NSString * const kIRWebAPIEngineRequestHTTPMethod = @"kIRWebAPIEngineRequestHTTPMethod"; +NSString * const kIRWebAPIEngineParser = @"kIRWebAPIEngineParser"; +NSString * const kIRWebAPIEngineResponseContextURLResponse = @"kIRWebAPIEngineResponseContextURLResponse"; +NSString * const kIRWebAPIRequestTimeout = @"kIRWebAPIRequestTimeout"; + +NSString * const kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey = @"kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey"; + +@implementation IRWebAPIEngine (OperationFiring) + +- (void) fireAPIRequestNamed:(NSString *)methodName withArguments:(NSDictionary *)arguments options:(NSDictionary *)options validator:(IRWebAPIResponseValidator)validatorBlock successHandler:(IRWebAPICallback)successBlock failureHandler:(IRWebAPICallback)failureBlock { + + IRWebAPIRequestOperation *operation = [self operationForMethod:methodName arguments:arguments contextOverride:^(IRWebAPIRequestContext *context) { + + if ([options objectForKey:kIRWebAPIEngineRequestHTTPBaseURL]) + context.baseURL = [options objectForKey:kIRWebAPIEngineRequestHTTPBaseURL]; + + [[options objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [context setValue:obj forHeaderField:key]; + }]; + + if ([options objectForKey:kIRWebAPIEngineRequestHTTPBody]) + context.body = [options objectForKey:kIRWebAPIEngineRequestHTTPBody]; + + [[options objectForKey:kIRWebAPIEngineRequestHTTPQueryParameters] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [context setValue:key forQueryParam:key]; + }]; + + if ([options objectForKey:kIRWebAPIEngineRequestHTTPMethod]) + context.method = [options objectForKey:kIRWebAPIEngineRequestHTTPMethod]; + + if ([options objectForKey:kIRWebAPIEngineParser]) + context.parser = [options objectForKey:kIRWebAPIEngineParser]; + + if ([options objectForKey:kIRWebAPIEngineResponseContextURLResponse]) + context.urlResponse = [options objectForKey:kIRWebAPIEngineResponseContextURLResponse]; + + if ([options objectForKey:kIRWebAPIRequestTimeout]) + context.timeout = [[options objectForKey:kIRWebAPIRequestTimeout] doubleValue]; + + [[options objectForKey:kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [context setValue:obj forFormURLEncodingField:key]; + }]; + + } validator:validatorBlock successBlock:successBlock failureBlock:failureBlock]; + + [self.queue addOperation:operation]; + +} + +@end diff --git a/IRWebAPIEngine.h b/IRWebAPIEngine.h index 1fa078b..e047efa 100644 --- a/IRWebAPIEngine.h +++ b/IRWebAPIEngine.h @@ -7,21 +7,17 @@ // #import -#import "IRWebAPIKit.h" -extern NSString * const kIRWebAPIEngineResponseDictionaryIncomingData; -extern NSString * const kIRWebAPIEngineResponseDictionaryOutgoingContext; -extern NSString * const kIRWebAPIEngineAssociatedDataStore; -extern NSString * const kIRWebAPIEngineAssociatedResponseContext; -extern NSString * const kIRWebAPIEngineAssociatedSuccessHandler; -extern NSString * const kIRWebAPIEngineAssociatedFailureHandler; -extern NSString * const kIRWebAPIEngineUnderlyingError; +#import "IRWebAPIKitDefines.h" +@class IRWebAPIRequestOperation, IRWebAPIEngineContext; @interface IRWebAPIEngine : NSObject -@property (nonatomic, readwrite, copy) IRWebAPIResponseParser parser; -@property (nonatomic, readonly, retain) IRWebAPIEngineContext *context; +- (id) initWithContext:(IRWebAPIEngineContext *)inContext; + +@property (nonatomic, readonly, strong) IRWebAPIEngineContext *context; +@property (nonatomic, readonly, strong) NSOperationQueue *queue; @property (nonatomic, readonly, retain) NSMutableArray *globalRequestPreTransformers; @property (nonatomic, readonly, retain) NSMutableDictionary *requestTransformers; @@ -31,28 +27,8 @@ extern NSString * const kIRWebAPIEngineUnderlyingError; @property (nonatomic, readonly, retain) NSMutableDictionary *responseTransformers; @property (nonatomic, readonly, retain) NSMutableArray *globalResponsePostTransformers; -- (id) initWithContext:(IRWebAPIEngineContext *)inContext; - -- (void) fireAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil validator:(IRWebAPIResposeValidator)inValidator successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler; +- (IRWebAPIRequestOperation *) operationForMethod:(NSString *)method arguments:(NSDictionary *)arguments validator:(IRWebAPIResponseValidator)validator successBlock:(IRWebAPICallback)successBlock failureBlock:(IRWebAPICallback)failureBlock; -- (NSMutableArray *) requestTransformersForMethodNamed:(NSString *)inMethodName; -- (NSMutableArray *) responseTransformersForMethodNamed:(NSString *)inMethodName; - -// Convenience. Putting them in a category does not assure compiler checking. - -- (void) fireAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler; - -- (void) fireAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler; +- (IRWebAPIRequestOperation *) operationForMethod:(NSString *)method arguments:(NSDictionary *)arguments contextOverride:(void(^)(IRWebAPIRequestContext *))overrideBlock validator:(IRWebAPIResponseValidator)validator successBlock:(IRWebAPICallback)successBlock failureBlock:(IRWebAPICallback)failureBlock; @end - - - - - -#import "IRWebAPIEngine+LocalCaching.h" -#import "IRWebAPIEngine+FormMultipart.h" - - - - diff --git a/IRWebAPIEngine.m b/IRWebAPIEngine.m index 76fdafb..a708b27 100644 --- a/IRWebAPIEngine.m +++ b/IRWebAPIEngine.m @@ -8,29 +8,12 @@ #import #import "IRWebAPIEngine.h" - - - - - -NSString * const kIRWebAPIEngineResponseDictionaryIncomingData = @"kIRWebAPIEngineResponseDictionaryIncomingData"; -NSString * const kIRWebAPIEngineResponseDictionaryOutgoingContext = @"kIRWebAPIEngineResponseDictionaryOutgoingContext"; - -NSString * const kIRWebAPIEngineAssociatedDataStore = @"kIRWebAPIEngineAssociatedDataStore"; -NSString * const kIRWebAPIEngineAssociatedResponseContext = @"kIRWebAPIEngineAssociatedResponseContext"; -NSString * const kIRWebAPIEngineAssociatedSuccessHandler = @"kIRWebAPIEngineAssociatedSuccessHandler"; -NSString * const kIRWebAPIEngineAssociatedFailureHandler = @"kIRWebAPIEngineAssociatedFailureHandler"; - -NSString * const kIRWebAPIEngineUnderlyingError = @"kIRWebAPIEngineUnderlyingError"; - - - - +#import "IRWebAPIRequestContext.h" +#import "IRWebAPIRequestOperation.h" +#import "IRWebAPIEngineContext.h" @interface IRWebAPIEngine () -@property (nonatomic, readwrite, retain) IRWebAPIEngineContext *context; - @property (nonatomic, readwrite, retain) NSMutableArray *globalRequestPreTransformers; @property (nonatomic, readwrite, retain) NSMutableDictionary *requestTransformers; @property (nonatomic, readwrite, retain) NSMutableArray *globalRequestPostTransformers; @@ -39,52 +22,23 @@ @interface IRWebAPIEngine () @property (nonatomic, readwrite, retain) NSMutableDictionary *responseTransformers; @property (nonatomic, readwrite, retain) NSMutableArray *globalResponsePostTransformers; -@property (nonatomic, readwrite, assign) dispatch_queue_t sharedDispatchQueue; - - -- (void) setInternalDataStore:(NSMutableData *)inDataStore forConnection:(NSURLConnection *)inConnection; -- (NSMutableData *) internalDataStoreForConnection:(NSURLConnection *)inConnection; - -- (void) setInternalResponseContext:(NSMutableDictionary *)inResponseContext forConnection:(NSURLConnection *)inConnection; -- (NSMutableDictionary *) internalResponseContextForConnection:(NSURLConnection *)inConnection; - -- (void) setInternalSuccessHandler:(void (^)(NSData *inResponse))inSuccessHandler forConnection:(NSURLConnection *)inConnection; -- (void (^)(NSData *inResponse)) internalSuccessHandlerForConnection:(NSURLConnection *)inConnection; +- (IRWebAPIRequestContext *) requestContextByTransformingContext:(IRWebAPIRequestContext *)inContext forMethodNamed:(NSString *)inMethodName; -- (void) setInternalFailureHandler:(void (^)(void))inFailureHandler forConnection:(NSURLConnection *)inConnection; -- (void (^)(void)) internalFailureHandlerForConnection:(NSURLConnection *)inConnection; - - -- (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil validator:(IRWebAPIResposeValidator)inValidator successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler; - -- (void) ensureResponseParserExistence; - -- (NSDictionary *) baseRequestContextWithMethodName:(NSString *)inMethodName arguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil; -- (NSDictionary *) requestContextByTransformingContext:(NSDictionary *)inContext forMethodNamed:(NSString *)inMethodName; -- (NSURLRequest *) requestWithContext:(NSDictionary *)inContext; - -- (NSDictionary *) parsedResponseForData:(NSData *)inData withContext:(NSDictionary *)inContext; -- (void) handleUnparsableResponseForData:(NSData *)inData context:(NSDictionary *)inContext; - -- (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse withRequestContext:(NSDictionary *)inRequestContext forMethodNamed:(NSString *)inMethodName; - -- (void) cleanUpForConnection:(NSURLConnection *)inConnection; +- (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse withRequestContext:(IRWebAPIRequestContext *)inRequestContext forMethodNamed:(NSString *)inMethodName; @end - - - @implementation IRWebAPIEngine -@synthesize parser, context; -@synthesize globalRequestPreTransformers, requestTransformers, globalRequestPostTransformers; -@synthesize globalResponsePreTransformers, responseTransformers, globalResponsePostTransformers; -@synthesize sharedDispatchQueue; - -# pragma mark - -# pragma mark Initializationand Memory Management +@synthesize context = _context; +@synthesize queue = _queue; +@synthesize globalRequestPreTransformers = _globalRequestPreTransformers; +@synthesize requestTransformers = _requestTransformers; +@synthesize globalRequestPostTransformers = _globalRequestPostTransformers; +@synthesize globalResponsePreTransformers = _globalResponsePreTransformers; +@synthesize responseTransformers = _responseTransformers; +@synthesize globalResponsePostTransformers = _globalResponsePostTransformers; - (id) initWithContext:(IRWebAPIEngineContext *)inContext { @@ -92,18 +46,19 @@ - (id) initWithContext:(IRWebAPIEngineContext *)inContext { if (!self) return nil; - context = inContext; + _context = inContext; - self.globalRequestPreTransformers = [NSMutableArray array]; - self.requestTransformers = [NSMutableDictionary dictionary]; - self.globalRequestPostTransformers = [NSMutableArray array]; - - self.globalResponsePreTransformers = [NSMutableArray array]; - self.responseTransformers = [NSMutableDictionary dictionary]; - self.globalResponsePostTransformers = [NSMutableArray array]; + _queue = [[NSOperationQueue alloc] init]; + _queue.maxConcurrentOperationCount = 8; + + _globalRequestPreTransformers = [NSMutableArray array]; + _requestTransformers = [NSMutableDictionary dictionary]; + _globalRequestPostTransformers = [NSMutableArray array]; + + _globalResponsePreTransformers = [NSMutableArray array]; + _responseTransformers = [NSMutableDictionary dictionary]; + _globalResponsePostTransformers = [NSMutableArray array]; - self.sharedDispatchQueue = dispatch_queue_create("com.iridia.WebAPIEngine.queue.main", NULL); - return self; } @@ -114,352 +69,75 @@ - (id) init { } -- (void) dealloc { - -#if !OS_OBJECT_USE_OBJC - dispatch_release(sharedDispatchQueue); -#endif - -} - - - - - -# pragma mark - -# pragma mark Helpers - -- (void) ensureResponseParserExistence { - - if (!self.parser) - self.parser = IRWebAPIResponseDefaultParserMake(); - -} - -- (NSDictionary *) parsedResponseForData:(NSData *)inData withContext:(NSDictionary *)inContext { - - IRWebAPIResponseParser parserBlock = [inContext objectForKey:kIRWebAPIEngineParser]; - - NSDictionary *parsedResponse = parserBlock(inData); - - if (parsedResponse) - return parsedResponse; - - [self handleUnparsableResponseForData:inData context:inContext]; - - return [NSDictionary dictionaryWithObjectsAndKeys: - - inData, kIRWebAPIEngineResponseDictionaryIncomingData, - inContext, kIRWebAPIEngineResponseDictionaryOutgoingContext, - - nil]; - -} - -- (void) handleUnparsableResponseForData:(NSData *)inData context:(NSDictionary *)inContext { - - NSLog(@"%@ %s Warning: unparsable response. Resetting returned response to an empty dictionary.", self, __PRETTY_FUNCTION__); - - return; - - NSMutableDictionary *displayedContext = [inContext mutableCopy]; - [displayedContext setObject:@"< REMOVED> " forKey:kIRWebAPIEngineRequestHTTPBody]; - -// This can potentially clog up the wirings -// IRWebAPIResponseParser defaultParser = IRWebAPIResponseDefaultParserMake(); -// NSDictionary *debugOutput = defaultParser(inData); -// NSLog(@"Default parser returns %@.", debugOutput ? (id)debugOutput : (id)@"- null -"); - -} - -- (void) fireAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler { - - dispatch_async(self.sharedDispatchQueue, ^ { - - dispatch_async(dispatch_get_current_queue(), [self executionBlockForAPIRequestNamed:inMethodName withArguments:inArgumentsOrNil options:nil validator:nil successHandler:inSuccessHandler failureHandler:inFailureHandler]); - - }); - -} - -- (void) fireAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil validator:(IRWebAPIResposeValidator)inValidator successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler { - - dispatch_async(self.sharedDispatchQueue, ^ { - - dispatch_async(dispatch_get_current_queue(), [self executionBlockForAPIRequestNamed:inMethodName withArguments:inArgumentsOrNil options:inOptionsOrNil validator:inValidator successHandler:inSuccessHandler failureHandler:inFailureHandler]); - - }); - -} - -- (void) fireAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler { - - dispatch_async(self.sharedDispatchQueue, ^ { - - dispatch_async(dispatch_get_current_queue(), [self executionBlockForAPIRequestNamed:inMethodName withArguments:inArgumentsOrNil options:inOptionsOrNil validator:nil successHandler:inSuccessHandler failureHandler:inFailureHandler]); - - }); - -} +- (IRWebAPIRequestOperation *) operationForMethod:(NSString *)method arguments:(NSDictionary *)arguments validator:(IRWebAPIResponseValidator)validator successBlock:(IRWebAPICallback)successBlock failureBlock:(IRWebAPICallback)failureBlock { -- (void) enqueueAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler { + return [self operationForMethod:method arguments:arguments contextOverride:nil validator:validator successBlock:successBlock failureBlock:failureBlock]; - dispatch_async(self.sharedDispatchQueue, ^ { - - dispatch_async(self.sharedDispatchQueue, [self executionBlockForAPIRequestNamed:inMethodName withArguments:inArgumentsOrNil options:inOptionsOrNil validator:nil successHandler:inSuccessHandler failureHandler:inFailureHandler]); - - }); - } - - - - - -# pragma mark - -# pragma mark Core - -- (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil validator:(IRWebAPIResposeValidator)inValidator successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler { +- (IRWebAPIRequestOperation *) operationForMethod:(NSString *)method arguments:(NSDictionary *)arguments contextOverride:(void(^)(IRWebAPIRequestContext *))overrideBlock validator:(IRWebAPIResponseValidator)validator successBlock:(IRWebAPICallback)successBlock failureBlock:(IRWebAPICallback)failureBlock { __weak IRWebAPIEngine *wSelf = self; - [self ensureResponseParserExistence]; - - void (^retryHandler)(void) = ^ { - - [self enqueueAPIRequestNamed:inMethodName withArguments:inArgumentsOrNil options:inOptionsOrNil successHandler:inSuccessHandler failureHandler:inFailureHandler]; + IRWebAPIRequestContext *baseContext = [IRWebAPIRequestContext new]; + baseContext.baseURL = [self.context baseURLForMethodNamed:method]; + baseContext.engineMethod = method; - }; + [arguments enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [baseContext setValue:obj forQueryParam:key]; + }]; - void (^notifyDelegateHandler)(void) = ^ { + if (overrideBlock) + overrideBlock(baseContext); - NSLog(@"Notifying delegate of connection finalization"); + IRWebAPIRequestContext *finalizedContext = [self requestContextByTransformingContext:baseContext forMethodNamed:method]; + IRWebAPIRequestOperation *operation = [[IRWebAPIRequestOperation alloc] initWithContext:finalizedContext]; - }; + __weak IRWebAPIRequestOperation *wOperation = operation; - NSDictionary *finalizedContext = [self requestContextByTransformingContext:[self baseRequestContextWithMethodName:inMethodName arguments:inArgumentsOrNil options:inOptionsOrNil] forMethodNamed:inMethodName]; - - NSURLRequest *request = [self requestWithContext:finalizedContext]; + [operation setCompletionBlock:^{ - void (^returnedBlock) (void) = ^ { - + IRWebAPIRequestState state = wOperation.state; + IRWebAPIRequestContext *context = wOperation.context; + NSDictionary *response = (NSDictionary *)wOperation.result; + dispatch_async(dispatch_get_main_queue(), ^{ + + NSCParameterAssert((state == IRWebAPIRequestStateSucceeded) || (state == IRWebAPIRequestStateFailed)); + + NSCParameterAssert(!response || [response isKindOfClass:[NSDictionary class]]); - NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; + NSDictionary *transformedResponse = [wSelf responseByTransformingResponse:response withRequestContext:context forMethodNamed:method]; - [self setInternalSuccessHandler: ^ (NSData *inResponse) { + if (state == IRWebAPIRequestStateSucceeded) { - BOOL shouldRetry = NO, notifyDelegate = NO; - - NSDictionary *responseContext = [wSelf internalResponseContextForConnection:connection]; - NSDictionary *parsedResponse = [wSelf parsedResponseForData:inResponse withContext:finalizedContext]; - NSDictionary *transformedResponse = [wSelf responseByTransformingResponse:parsedResponse withRequestContext:responseContext forMethodNamed:inMethodName]; - - if ((inValidator != nil) && (!inValidator(transformedResponse, responseContext))) { + if ((validator != nil) && (!validator(transformedResponse, context))) { - if (inFailureHandler) - inFailureHandler(transformedResponse, responseContext, ¬ifyDelegate, &shouldRetry); + if (failureBlock) + failureBlock(transformedResponse, context); } else { - if (inSuccessHandler) - inSuccessHandler(transformedResponse, responseContext, ¬ifyDelegate, &shouldRetry); + if (successBlock) + successBlock(transformedResponse, context); } - - if (shouldRetry) retryHandler(); - if (notifyDelegate) notifyDelegateHandler(); - - [wSelf cleanUpForConnection:connection]; - - } forConnection:connection]; + } else { - [self setInternalFailureHandler: ^ { - - BOOL shouldRetry = NO, notifyDelegate = NO; - NSMutableDictionary *responseContext = [wSelf internalResponseContextForConnection:connection]; - NSDictionary *transformedResopnse = [wSelf responseByTransformingResponse:[NSDictionary dictionary] withRequestContext:responseContext forMethodNamed:inMethodName]; - - if (inFailureHandler) - inFailureHandler(transformedResopnse, responseContext, ¬ifyDelegate, &shouldRetry); - - if (shouldRetry) retryHandler(); - if (notifyDelegate) notifyDelegateHandler(); + if (failureBlock) + failureBlock(transformedResponse, context); + + } - [wSelf cleanUpForConnection:connection]; - - } forConnection:connection]; - - - [self setInternalDataStore:[NSMutableData data] forConnection:connection]; - [self setInternalResponseContext:[NSMutableDictionary dictionaryWithObjectsAndKeys: - - finalizedContext, kIRWebAPIEngineResponseContextOriginalRequestContext, - - nil] forConnection:connection]; - - [connection start]; - }); - }; + }]; - return [returnedBlock copy]; + return operation; } - - - - -# pragma mark - -# pragma mark Connection Delegation - -- (void) connection:(NSURLConnection *)inConnection didReceiveData:(NSData *)inData { - - dispatch_async(self.sharedDispatchQueue, ^{ - - [[self internalDataStoreForConnection:inConnection] appendData:inData]; - - }); - -} - -- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { - - dispatch_async(self.sharedDispatchQueue, ^{ - - NSMutableDictionary *responseContext = [self internalResponseContextForConnection:connection]; - [responseContext setObject:response forKey:kIRWebAPIEngineResponseContextURLResponse]; - - }); - -} - -- (void) connectionDidFinishLoading:(NSURLConnection *)inConnection { - - dispatch_async(self.sharedDispatchQueue, ^{ - - @try { - - [self internalSuccessHandlerForConnection:inConnection]([self internalDataStoreForConnection:inConnection]); - - } @catch (NSException *e) { - - [self internalFailureHandlerForConnection:inConnection](); - - } - - }); - -} - -- (void) connection:(NSURLConnection *)inConnection didFailWithError:(NSError *)error { - - dispatch_async(self.sharedDispatchQueue, ^{ - - [[self internalResponseContextForConnection:inConnection] setObject:error forKey:kIRWebAPIEngineUnderlyingError]; - [self internalFailureHandlerForConnection:inConnection](); - - }); - -} - -- (BOOL) connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { - - return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]; - -} - -- (void) connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { - - if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) - if ([[self.context.baseURL host] isEqualToString:challenge.protectionSpace.host]) - [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; - - [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; - -} - - - - - -# pragma mark - -# pragma mark Associated Objects - -// Notice that blocks are made on the stack so they must be copied before being stored away - - -- (void) setInternalSuccessHandler:(void (^)(NSData *inResponse))inSuccessHandler forConnection:(NSURLConnection *)inConnection { - - objc_setAssociatedObject(inConnection, CFBridgingRetain(kIRWebAPIEngineAssociatedSuccessHandler), inSuccessHandler, OBJC_ASSOCIATION_COPY); - -} - -- (void (^)(NSData *inResponse)) internalSuccessHandlerForConnection:(NSURLConnection *)inConnection { - - return objc_getAssociatedObject(inConnection, (__bridge const void *)(kIRWebAPIEngineAssociatedSuccessHandler)); - -} - -- (void) setInternalFailureHandler:(void (^)(void))inFailureHandler forConnection:(NSURLConnection *)inConnection { - - objc_setAssociatedObject(inConnection, CFBridgingRetain(kIRWebAPIEngineAssociatedFailureHandler), inFailureHandler, OBJC_ASSOCIATION_COPY); - -} - -- (void (^)(void)) internalFailureHandlerForConnection:(NSURLConnection *)inConnection { - - return objc_getAssociatedObject(inConnection, (__bridge const void *)(kIRWebAPIEngineAssociatedFailureHandler)); - -} - -- (void) setInternalDataStore:(NSMutableData *)inDataStore forConnection:(NSURLConnection *)inConnection { - - objc_setAssociatedObject(inConnection, (__bridge const void *)(kIRWebAPIEngineAssociatedDataStore), inDataStore, OBJC_ASSOCIATION_RETAIN); - -} - -- (NSMutableData *) internalDataStoreForConnection:(NSURLConnection *)inConnection { - - return objc_getAssociatedObject(inConnection, (__bridge const void *)(kIRWebAPIEngineAssociatedDataStore)); - -} - -- (void) setInternalResponseContext:(NSMutableDictionary *)inResponseContext forConnection:(NSURLConnection *)inConnection { - - objc_setAssociatedObject(inConnection, (__bridge const void *)(kIRWebAPIEngineAssociatedResponseContext), inResponseContext, OBJC_ASSOCIATION_RETAIN); - -} - -- (NSMutableDictionary *) internalResponseContextForConnection:(NSURLConnection *)inConnection { - - return objc_getAssociatedObject(inConnection, (__bridge const void *)(kIRWebAPIEngineAssociatedResponseContext)); - -} - -- (void) cleanUpForConnection:(NSURLConnection *)inConnection { - - dispatch_async(dispatch_get_main_queue(), ^{ - - objc_removeAssociatedObjects(inConnection); - - }); - -} - - - - - - - - - - - (NSMutableArray *) requestTransformersForMethodNamed:(NSString *)inMethodName { NSMutableArray *returnedArray = [self.requestTransformers objectForKey:inMethodName]; @@ -490,78 +168,20 @@ - (NSMutableArray *) responseTransformersForMethodNamed:(NSString *)inMethodName } - - - - -- (NSDictionary *) baseRequestContextWithMethodName:(NSString *)inMethodName arguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil { - - NSMutableDictionary *arguments = [NSMutableDictionary dictionary]; - - if (inArgumentsOrNil) for (id argumentKey in [inArgumentsOrNil keysOfEntriesPassingTest:^(id key, id object, BOOL *stop) { - - if ([object isEqual:@""]) return NO; - if ([object isEqual:[NSNull null]]) return NO; - - return YES; - - }]) [arguments setObject:[inArgumentsOrNil objectForKey:argumentKey] forKey:argumentKey]; - - - NSURL *baseURL = [inOptionsOrNil objectForKey:kIRWebAPIEngineRequestHTTPBaseURL]; - baseURL = baseURL ? baseURL : [self.context baseURLForMethodNamed:inMethodName]; - - NSMutableDictionary *headerFields = [inOptionsOrNil objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - headerFields = headerFields ? [headerFields mutableCopy] : [NSMutableDictionary dictionary]; - - id httpBody = [inOptionsOrNil objectForKey:kIRWebAPIEngineRequestHTTPBody]; - httpBody = httpBody ? httpBody : [NSNull null]; - - NSString *httpMethod = [inOptionsOrNil objectForKey:kIRWebAPIEngineRequestHTTPMethod]; - httpMethod = httpMethod ? [httpMethod copy] : @"GET"; - - IRWebAPIResponseParser responseParser = [inOptionsOrNil objectForKey:kIRWebAPIEngineParser]; - responseParser = responseParser ? responseParser : self.parser; - - NSNumber *timeoutValue = [inOptionsOrNil objectForKey:kIRWebAPIRequestTimeout]; - timeoutValue = timeoutValue ? timeoutValue : [NSNumber numberWithDouble:60.0]; - - NSMutableDictionary *transformedContext = [NSMutableDictionary dictionaryWithObjectsAndKeys: - - baseURL, kIRWebAPIEngineRequestHTTPBaseURL, - headerFields, kIRWebAPIEngineRequestHTTPHeaderFields, - arguments, kIRWebAPIEngineRequestHTTPQueryParameters, - httpBody, kIRWebAPIEngineRequestHTTPBody, - httpMethod, kIRWebAPIEngineRequestHTTPMethod, - responseParser, kIRWebAPIEngineParser, - inMethodName, kIRWebAPIEngineIncomingMethodName, - timeoutValue, kIRWebAPIRequestTimeout, - - nil]; - - - for (id optionValueKey in inOptionsOrNil) - [transformedContext setValue:[inOptionsOrNil valueForKey:optionValueKey] forKey:optionValueKey]; - - return [transformedContext copy]; - -} - -- (NSDictionary *) requestContextByTransformingContext:(NSDictionary *)inContext forMethodNamed:(NSString *)inMethodName { +- (IRWebAPIRequestContext *) requestContextByTransformingContext:(IRWebAPIRequestContext *)inContext forMethodNamed:(NSString *)inMethodName { NSMutableArray *allTransformers = [NSMutableArray array]; [allTransformers addObjectsFromArray:self.globalRequestPreTransformers]; NSArray *methodSpecificTransformers = [self requestTransformersForMethodNamed:inMethodName]; - if (methodSpecificTransformers) { [allTransformers addObjectsFromArray:methodSpecificTransformers]; } [allTransformers addObjectsFromArray:self.globalRequestPostTransformers]; - NSDictionary *currentContext = inContext; + IRWebAPIRequestContext *currentContext = inContext; for (IRWebAPIRequestContextTransformer aTransformer in allTransformers) currentContext = aTransformer(currentContext); @@ -570,7 +190,7 @@ - (NSDictionary *) requestContextByTransformingContext:(NSDictionary *)inContext } -- (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse withRequestContext:(NSDictionary *)inRequestContext forMethodNamed:(NSString *)inMethodName { +- (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse withRequestContext:(IRWebAPIRequestContext *)inRequestContext forMethodNamed:(NSString *)inMethodName { NSMutableArray *allTransformers = [NSMutableArray array]; [allTransformers addObjectsFromArray:self.globalResponsePreTransformers]; @@ -586,38 +206,4 @@ - (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse wit } - - - - -- (NSURLRequest *) requestWithContext:(NSDictionary *)inContext { - - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:IRWebAPIRequestURLWithQueryParameters( - - (NSURL *)[inContext objectForKey:kIRWebAPIEngineRequestHTTPBaseURL], - [inContext objectForKey:kIRWebAPIEngineRequestHTTPQueryParameters] - - ) cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:[[inContext objectForKey:kIRWebAPIRequestTimeout] doubleValue]]; - - [request setHTTPShouldHandleCookies:NO]; - - NSDictionary *headerFields; - if ((headerFields = [inContext objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields])) - for (NSString *headerFieldKey in headerFields) - [request setValue:[headerFields objectForKey:headerFieldKey] forHTTPHeaderField:headerFieldKey]; - - NSData *httpBody = [inContext objectForKey:kIRWebAPIEngineRequestHTTPBody]; - if (![httpBody isEqual:[NSNull null]]) - [request setHTTPBody:httpBody]; - - [request setHTTPMethod:[inContext objectForKey:kIRWebAPIEngineRequestHTTPMethod]]; - - return [request copy]; - -} - - - - - @end diff --git a/IRWebAPIHelpers.m b/IRWebAPIHelpers.m index 2c3e4fb..3cfc2dd 100644 --- a/IRWebAPIHelpers.m +++ b/IRWebAPIHelpers.m @@ -386,8 +386,8 @@ BOOL IRWebAPIKitValidResponse (id inObject) { [queryPairExpression enumerateMatchesInString:query options:0 range:queryFullRange usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { - __block NSString *currentArgumentName = nil; - __block NSString *currentArgumentValue = nil; + NSString *currentArgumentName = nil; + NSString *currentArgumentValue = nil; NSUInteger numberOfRanges = result.numberOfRanges; if (!numberOfRanges) diff --git a/IRWebAPIInterceptor.h b/IRWebAPIInterceptor.h new file mode 100644 index 0000000..a2fc036 --- /dev/null +++ b/IRWebAPIInterceptor.h @@ -0,0 +1,15 @@ +// +// IRWebAPIInterceptor.h +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import + +@interface IRWebAPIInterceptor : NSObject + +@property (nonatomic, readwrite, weak) id receiver; + +@end diff --git a/IRWebAPIInterceptor.m b/IRWebAPIInterceptor.m new file mode 100644 index 0000000..38a1847 --- /dev/null +++ b/IRWebAPIInterceptor.m @@ -0,0 +1,32 @@ +// +// IRWebAPIInterceptor.m +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import "IRWebAPIInterceptor.h" + +@implementation IRWebAPIInterceptor +@synthesize receiver = _receiver; + +- (id) forwardingTargetForSelector:(SEL)aSelector { + + if ([_receiver respondsToSelector:aSelector]) + return _receiver; + + return [super forwardingTargetForSelector:aSelector]; + +} + +- (BOOL) respondsToSelector:(SEL)aSelector { + + if ([_receiver respondsToSelector:aSelector]) + return YES; + + return [super respondsToSelector:aSelector]; + +} + +@end diff --git a/IRWebAPIInterface+Validators.h b/IRWebAPIInterface+Validators.h index 7626792..a4cd195 100644 --- a/IRWebAPIInterface+Validators.h +++ b/IRWebAPIInterface+Validators.h @@ -12,6 +12,6 @@ @interface IRWebAPIInterface (Validators) -+ (IRWebAPIResposeValidator) defaultNoErrorValidator; ++ (IRWebAPIResponseValidator) defaultNoErrorValidator; @end diff --git a/IRWebAPIInterface+Validators.m b/IRWebAPIInterface+Validators.m index 2746813..6e0319c 100644 --- a/IRWebAPIInterface+Validators.m +++ b/IRWebAPIInterface+Validators.m @@ -11,13 +11,11 @@ @implementation IRWebAPIInterface (Validators) -+ (IRWebAPIResposeValidator) defaultNoErrorValidator { ++ (IRWebAPIResponseValidator) defaultNoErrorValidator { - return [(^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { + return [(^ (NSDictionary *response, IRWebAPIRequestContext *context) { - NSHTTPURLResponse *response = (NSHTTPURLResponse *)[inResponseContext objectForKey:kIRWebAPIEngineResponseContextURLResponse]; - - return (response.statusCode == 200); + return (context.urlResponse.statusCode == 200); }) copy]; diff --git a/IRWebAPIKit.h b/IRWebAPIKit.h index e554f93..f8c37dd 100644 --- a/IRWebAPIKit.h +++ b/IRWebAPIKit.h @@ -15,6 +15,12 @@ #import "IRWebAPIEngine.h" #import "IRWebAPIEngineContext.h" + +#import "IRWebAPIEngine+OperationFiring.h" +#import "IRWebAPIEngine+FormMultipart.h" +#import "IRWebAPIEngine+FormURLEncoding.h" +#import "IRWebAPIEngine+LocalCaching.h" + #import "IRWebAPIAuthenticator.h" #import "IRWebAPICredentials.h" #import "IRWebAPIInterface.h" @@ -31,7 +37,8 @@ #import "IRRemoteResourcesManager.h" - +#import "IRWebAPIRequestContext.h" +#import "IRWebAPIRequestOperation.h" diff --git a/IRWebAPIKit.xcodeproj/project.pbxproj b/IRWebAPIKit.xcodeproj/project.pbxproj index 6f0322d..5df6cca 100644 --- a/IRWebAPIKit.xcodeproj/project.pbxproj +++ b/IRWebAPIKit.xcodeproj/project.pbxproj @@ -65,6 +65,12 @@ FF896A6B12A5666D00AE2AF3 /* IRWebAPIInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = FF896A6912A5666D00AE2AF3 /* IRWebAPIInterface.h */; }; FF896A6C12A5666D00AE2AF3 /* IRWebAPIInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = FF896A6A12A5666D00AE2AF3 /* IRWebAPIInterface.m */; }; FF8974E212A57F3800AE2AF3 /* IRWebAPIInterfaceXOAuthAuthenticating.h in Headers */ = {isa = PBXBuildFile; fileRef = FF8974E112A57F3800AE2AF3 /* IRWebAPIInterfaceXOAuthAuthenticating.h */; }; + FF9838A31598313D00CFF2DF /* IRWebAPIRequestContext.h in Headers */ = {isa = PBXBuildFile; fileRef = FF9838A11598313D00CFF2DF /* IRWebAPIRequestContext.h */; }; + FF9838A41598313D00CFF2DF /* IRWebAPIRequestContext.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9838A21598313D00CFF2DF /* IRWebAPIRequestContext.m */; }; + FF9838A815984A4A00CFF2DF /* IRWebAPIRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = FF9838A615984A4A00CFF2DF /* IRWebAPIRequestOperation.h */; }; + FF9838A915984A4A00CFF2DF /* IRWebAPIRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9838A715984A4A00CFF2DF /* IRWebAPIRequestOperation.m */; }; + FF9838AC1598502B00CFF2DF /* IRWebAPIInterceptor.h in Headers */ = {isa = PBXBuildFile; fileRef = FF9838AA1598502B00CFF2DF /* IRWebAPIInterceptor.h */; }; + FF9838AD1598502B00CFF2DF /* IRWebAPIInterceptor.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9838AB1598502B00CFF2DF /* IRWebAPIInterceptor.m */; }; FF9AFB4212EC59040037E930 /* IRWebAPIEngine+LocalCaching.h in Headers */ = {isa = PBXBuildFile; fileRef = FF9AFB4012EC59040037E930 /* IRWebAPIEngine+LocalCaching.h */; }; FF9AFB4312EC59040037E930 /* IRWebAPIEngine+LocalCaching.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB4112EC59040037E930 /* IRWebAPIEngine+LocalCaching.m */; }; FF9AFB4C12EC597C0037E930 /* IRWebAPIKitDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = FF9AFB4B12EC597C0037E930 /* IRWebAPIKitDefines.h */; }; @@ -74,6 +80,8 @@ FF9AFBF312EC5E9F0037E930 /* IRWebAPIKitDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB7F12EC5CB80037E930 /* IRWebAPIKitDefines.m */; }; FFB882B714234CBF00DA2876 /* IRRemoteResourceDownloadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = FFB882B514234CBF00DA2876 /* IRRemoteResourceDownloadOperation.h */; }; FFB882B814234CBF00DA2876 /* IRRemoteResourceDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = FFB882B614234CBF00DA2876 /* IRRemoteResourceDownloadOperation.m */; }; + FFBEE72E15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.h in Headers */ = {isa = PBXBuildFile; fileRef = FFBEE72C15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.h */; }; + FFBEE72F15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.m in Sources */ = {isa = PBXBuildFile; fileRef = FFBEE72D15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.m */; }; FFDB8EFD15943C7800FA7E9B /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFDB8EFC15943C7800FA7E9B /* MobileCoreServices.framework */; }; FFDB8EFE15943C8100FA7E9B /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFDB8EFC15943C7800FA7E9B /* MobileCoreServices.framework */; }; FFF5AC741470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h in Headers */ = {isa = PBXBuildFile; fileRef = FFF5AC721470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h */; }; @@ -140,6 +148,12 @@ FF896A6912A5666D00AE2AF3 /* IRWebAPIInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIInterface.h; sourceTree = ""; }; FF896A6A12A5666D00AE2AF3 /* IRWebAPIInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIInterface.m; sourceTree = ""; }; FF8974E112A57F3800AE2AF3 /* IRWebAPIInterfaceXOAuthAuthenticating.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIInterfaceXOAuthAuthenticating.h; sourceTree = ""; }; + FF9838A11598313D00CFF2DF /* IRWebAPIRequestContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIRequestContext.h; sourceTree = ""; }; + FF9838A21598313D00CFF2DF /* IRWebAPIRequestContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIRequestContext.m; sourceTree = ""; }; + FF9838A615984A4A00CFF2DF /* IRWebAPIRequestOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIRequestOperation.h; sourceTree = ""; }; + FF9838A715984A4A00CFF2DF /* IRWebAPIRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIRequestOperation.m; sourceTree = ""; }; + FF9838AA1598502B00CFF2DF /* IRWebAPIInterceptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIInterceptor.h; sourceTree = ""; }; + FF9838AB1598502B00CFF2DF /* IRWebAPIInterceptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIInterceptor.m; sourceTree = ""; }; FF9AFB4012EC59040037E930 /* IRWebAPIEngine+LocalCaching.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPIEngine+LocalCaching.h"; sourceTree = ""; }; FF9AFB4112EC59040037E930 /* IRWebAPIEngine+LocalCaching.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPIEngine+LocalCaching.m"; sourceTree = ""; }; FF9AFB4B12EC597C0037E930 /* IRWebAPIKitDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIKitDefines.h; sourceTree = ""; }; @@ -148,6 +162,8 @@ FF9AFB7F12EC5CB80037E930 /* IRWebAPIKitDefines.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIKitDefines.m; sourceTree = ""; }; FFB882B514234CBF00DA2876 /* IRRemoteResourceDownloadOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRRemoteResourceDownloadOperation.h; sourceTree = ""; }; FFB882B614234CBF00DA2876 /* IRRemoteResourceDownloadOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRRemoteResourceDownloadOperation.m; sourceTree = ""; }; + FFBEE72C15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPIEngine+OperationFiring.h"; sourceTree = ""; }; + FFBEE72D15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPIEngine+OperationFiring.m"; sourceTree = ""; }; FFDB8EFC15943C7800FA7E9B /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; FFE2607212D084CB001AF1AF /* IRWebAPIKitEntityDefinesGenerator.rb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.ruby; path = IRWebAPIKitEntityDefinesGenerator.rb; sourceTree = ""; }; FFF5AC721470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPIEngine+ExternalTransforms.h"; sourceTree = ""; }; @@ -245,6 +261,14 @@ FF7408981296B06F00571D46 /* IRWebAPIEngineContext.m */, FF7408451296A94900571D46 /* IRWebAPIEngine.h */, FF7408461296A94900571D46 /* IRWebAPIEngine.m */, + FFBEE72C15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.h */, + FFBEE72D15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.m */, + FF9838A11598313D00CFF2DF /* IRWebAPIRequestContext.h */, + FF9838A21598313D00CFF2DF /* IRWebAPIRequestContext.m */, + FF9838A615984A4A00CFF2DF /* IRWebAPIRequestOperation.h */, + FF9838A715984A4A00CFF2DF /* IRWebAPIRequestOperation.m */, + FF9838AA1598502B00CFF2DF /* IRWebAPIInterceptor.h */, + FF9838AB1598502B00CFF2DF /* IRWebAPIInterceptor.m */, FF9AFB4012EC59040037E930 /* IRWebAPIEngine+LocalCaching.h */, FF9AFB4112EC59040037E930 /* IRWebAPIEngine+LocalCaching.m */, FF9AFB7112EC5C060037E930 /* IRWebAPIEngine+FormMultipart.h */, @@ -391,6 +415,10 @@ FFB882B714234CBF00DA2876 /* IRRemoteResourceDownloadOperation.h in Headers */, FF7EB68A1467B876002718DC /* IRWebAPIEngine+FormURLEncoding.h in Headers */, FFF5AC741470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h in Headers */, + FF9838A31598313D00CFF2DF /* IRWebAPIRequestContext.h in Headers */, + FF9838A815984A4A00CFF2DF /* IRWebAPIRequestOperation.h in Headers */, + FF9838AC1598502B00CFF2DF /* IRWebAPIInterceptor.h in Headers */, + FFBEE72E15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -567,6 +595,10 @@ FFB882B814234CBF00DA2876 /* IRRemoteResourceDownloadOperation.m in Sources */, FF7EB68B1467B876002718DC /* IRWebAPIEngine+FormURLEncoding.m in Sources */, FFF5AC751470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m in Sources */, + FF9838A41598313D00CFF2DF /* IRWebAPIRequestContext.m in Sources */, + FF9838A915984A4A00CFF2DF /* IRWebAPIRequestOperation.m in Sources */, + FF9838AD1598502B00CFF2DF /* IRWebAPIInterceptor.m in Sources */, + FFBEE72F15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -724,6 +756,7 @@ buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_OBJCPP_ARC_ABI = YES; + COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; GCC_C_LANGUAGE_STANDARD = c99; GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; @@ -739,6 +772,7 @@ buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_OBJCPP_ARC_ABI = YES; + COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = YES; GCC_C_LANGUAGE_STANDARD = c99; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; diff --git a/IRWebAPIKitDefines.h b/IRWebAPIKitDefines.h index 8b3a471..a6ad666 100644 --- a/IRWebAPIKitDefines.h +++ b/IRWebAPIKitDefines.h @@ -12,129 +12,12 @@ @class IRWebAPIEngineContext; @class IRWebAPIAuthenticator; @class IRWebAPIInterface; - - - - - -#pragma mark Blocks +@class IRWebAPIRequestContext; typedef NSDictionary * (^IRWebAPIResponseParser) (NSData *inData); - -// The parser makes a dictionary from a NSData. - - -typedef NSDictionary * (^IRWebAPIRequestContextTransformer) (NSDictionary *inOriginalContext); - -// The transformer returns a transformed context dictionary. - - -typedef NSDictionary * (^IRWebAPIResponseContextTransformer) (NSDictionary *inParsedResponse, NSDictionary *inResponseContext); - -// The transformer returns a transformed context dictionary, and is given a change to reference the response context. -// The latter is not mutable. - - -typedef BOOL (^IRWebAPIResposeValidator) (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext); - -// The validator returns a BOOL regarding to the parsed and transformed response. - - -typedef void (^IRWebAPICallback) (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry); - -// The callback takes an engine and a response, then optionally tells the engine whether to notify its delegate or retry. -// inResponseContext contains lower-level objects, like NSURLResponse. -// *&outNotifyDelegate defaults to YES -// *&outShouldRetry defaults to NO - - -typedef void (^IRWebAPIAuthenticatorCallback) (IRWebAPIAuthenticator *inAuthenticator, BOOL isAuthenticated, BOOL *inShouldRetry); - -// The authenticator callback takes an authenticator, and its authentication status. -// If necessary, the block works with the authenticator and can tell it to retry authenticating. - - -typedef void (^IRWebAPIInterfaceCallback) (NSDictionary *inResponseOrNil, BOOL *outNotifyDelegate, BOOL *outShouldRetry); - -// The callback takes the response, then optionally tells the interface whether to notify its delegate or retry. - - -typedef void (^IRWebAPIEngineExecutionBlock) (void); - -// Internal. - - - - - -#pragma mark IRWebAPITransformer Context Dictionary Keys - -extern NSString * const kIRWebAPIEngineRequestHTTPBaseURL; - -// Expected to be a NSURL, and well it should be there - - -extern NSString * const kIRWebAPIEngineRequestHTTPHeaderFields; - -// Expected to be a dictionary - - -extern NSString * const kIRWebAPIEngineRequestHTTPPOSTParameters; - -// Expected to be a dictionary, that contains NSString / NSData objects. Everything is in utf-8 or octet. -// If not blank, IRWebAPIEngine makes the HTTP body from the parameters. -// Notice that to use POST parameters, a new transformer block that grabs the correct stuff under this key from the context and adds it to the - - -extern NSString * const kIRWebAPIEngineRequestHTTPBody; - -// Expected to be NSData, or [NSNull null] for custom HTTP body handling. -// If used with IRWebAPIEngineRequestHTTPPOSTParameters, an exception will be thrown. - - -extern NSString * const kIRWebAPIEngineRequestHTTPQueryParameters; - -// Expected to be a dictionary - - -extern NSString * const kIRWebAPIEngineRequestHTTPMethod; - -// Expected to be POST, GET, whatever. Must be POST if IRWebAPIEngineHTTPPOSTParameters is defined. - - -extern NSString * const kIRWebAPIEngineParser; - -// Expected to be a IRWebAPIResponseParser. Exposed to allow custom response parsing for “some methods”. - - -extern NSString * const kIRWebAPIEngineIncomingMethodName; - -// The string that was passed to -fireMethodNamed: - - -extern NSString * const kIRWebAPIRequestTimeout; - -// +[NSNumber numberWithDouble:]. Default is 60. - - - - - - -#pragma mark IRWebAPIEngine Response Context Dictionary Keys - -extern NSString * const kIRWebAPIEngineResponseContextURLResponse; -extern NSString * const kIRWebAPIEngineResponseContextURLResponseName DEPRECATED_ATTRIBUTE; - -// We send a response context to IRWebAPICallback blocks. -// This contains the vanilla NSURLResponse object. - - -extern NSString * const kIRWebAPIEngineResponseContextOriginalRequestContext; -extern NSString * const kIRWebAPIEngineResponseContextOriginalRequestContextName DEPRECATED_ATTRIBUTE; - -// This key gets the original request context. - - - - +typedef IRWebAPIRequestContext * (^IRWebAPIRequestContextTransformer) (IRWebAPIRequestContext *context); +typedef NSDictionary * (^IRWebAPIResponseContextTransformer) (NSDictionary *inParsedResponse, IRWebAPIRequestContext *inResponseContext); +typedef BOOL (^IRWebAPIResponseValidator) (NSDictionary *inResponseOrNil, IRWebAPIRequestContext *inResponseContext); +typedef void (^IRWebAPICallback) (NSDictionary *response, IRWebAPIRequestContext *context); +typedef void (^IRWebAPIAuthenticatorCallback) (IRWebAPIAuthenticator *inAuthenticator, BOOL isAuthenticated); +typedef void (^IRWebAPIInterfaceCallback) (NSDictionary *inResponseOrNil); diff --git a/IRWebAPIKitDefines.m b/IRWebAPIKitDefines.m index aec099d..6eac395 100644 --- a/IRWebAPIKitDefines.m +++ b/IRWebAPIKitDefines.m @@ -7,17 +7,3 @@ // #import "IRWebAPIKitDefines.h" - -NSString * const kIRWebAPIEngineRequestHTTPBaseURL = @"kIRWebAPIEngineRequestHTTPBaseURL"; -NSString * const kIRWebAPIEngineRequestHTTPHeaderFields = @"kIRWebAPIEngineRequestHTTPHeaderFields"; -NSString * const kIRWebAPIEngineRequestHTTPPOSTParameters = @"kIRWebAPIEngineRequestHTTPPOSTParameters"; -NSString * const kIRWebAPIEngineRequestHTTPBody = @"kIRWebAPIEngineRequestHTTPBody"; -NSString * const kIRWebAPIEngineRequestHTTPQueryParameters = @"kIRWebAPIEngineRequestHTTPQueryParameters"; -NSString * const kIRWebAPIEngineRequestHTTPMethod = @"kIRWebAPIEngineRequestHTTPMethod"; -NSString * const kIRWebAPIEngineParser = @"kIRWebAPIEngineParser"; -NSString * const kIRWebAPIEngineIncomingMethodName = @"kIRWebAPIEngineIncomingMethodName"; -NSString * const kIRWebAPIEngineResponseContextURLResponse = @"kIRWebAPIEngineResponseContextURLResponse"; -NSString * const kIRWebAPIEngineResponseContextURLResponseName = @"kIRWebAPIEngineResponseContextURLResponse"; -NSString * const kIRWebAPIEngineResponseContextOriginalRequestContext = @"kIRWebAPIEngineResponseContextOriginalRequestContext"; -NSString * const kIRWebAPIEngineResponseContextOriginalRequestContextName = @"kIRWebAPIEngineResponseContextOriginalRequestContext"; -NSString * const kIRWebAPIRequestTimeout = @"kIRWebAPIRequestTimeout"; diff --git a/IRWebAPIRequestContext.h b/IRWebAPIRequestContext.h new file mode 100644 index 0000000..480ec50 --- /dev/null +++ b/IRWebAPIRequestContext.h @@ -0,0 +1,38 @@ +// +// IRWebAPIRequestContext.h +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import + +#import "IRWebAPIKitDefines.h" + +@interface IRWebAPIRequestContext : NSObject + +@property (nonatomic, readwrite, copy) NSURL *baseURL; +@property (nonatomic, readwrite, copy) NSString *method; +@property (nonatomic, readwrite, copy) NSString *engineMethod; +@property (nonatomic, readwrite, copy) IRWebAPIResponseParser parser; + +@property (nonatomic, readwrite, copy) NSData *body; +@property (nonatomic, readwrite, assign) NSTimeInterval timeout; + +@property (nonatomic, readonly, copy) NSDictionary *headerFields; +- (void) removeAllHeaderFieldValues; +- (void) setValue:(id)obj forHeaderField:(NSString *)key; + +@property (nonatomic, readonly, copy) NSDictionary *queryParams; +- (void) removeAllQueryParamValues; +- (void) setValue:(id)obj forQueryParam:(NSString *)key; + +@property (nonatomic, readonly, copy) NSDictionary *userInfo; +- (void) removeAllUserInfoValues; +- (void) setValue:(id)obj forUserInfo:(NSString *)key; + +@property (nonatomic, readwrite, strong) NSHTTPURLResponse *urlResponse; +@property (nonatomic, readwrite, strong) NSError *error; + +@end diff --git a/IRWebAPIRequestContext.m b/IRWebAPIRequestContext.m new file mode 100644 index 0000000..27cf5c2 --- /dev/null +++ b/IRWebAPIRequestContext.m @@ -0,0 +1,142 @@ +// +// IRWebAPIRequestContext.m +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import "IRWebAPIRequestContext.h" +#import "IRWebAPIResponseParser.h" + +static NSString * const kHeaderFields = @"headerFields"; +static NSString * const kQueryParams = @"queryParams"; +static NSString * const kUserInfo = @"userInfo"; + +@implementation IRWebAPIRequestContext { +@package + NSMutableDictionary *_headerFields; + NSMutableDictionary *_queryParams; + NSMutableDictionary *_userInfo; +} + +@synthesize baseURL = _baseURL; +@synthesize method = _method; +@synthesize engineMethod = _engineMethod; +@synthesize parser = _parser; +@synthesize body = _body; +@synthesize timeout = _timeout; +@synthesize urlResponse = _urlResponse; +@synthesize error = _error; + +- (id) init { + + self = [super init]; + if (!self) + return nil; + + _method = @"GET"; + + _timeout = 60.0f; + + _headerFields = [NSMutableDictionary dictionary]; + _queryParams = [NSMutableDictionary dictionary]; + _userInfo = [NSMutableDictionary dictionary]; + + _parser = [IRWebAPIResponseDefaultJSONParserMake() copy]; + + return self; + +} + +- (void) setBody:(NSData *)body { + + _body = body; + +} + +- (NSDictionary *) headerFields { + + return [_headerFields copy]; + +} + +- (void) removeAllHeaderFieldValues { + + [self willChangeValueForKey:kHeaderFields]; + [_headerFields removeAllObjects]; + [self didChangeValueForKey:kHeaderFields]; + +} + +- (void) setValue:(id)obj forHeaderField:(NSString *)key { + + [self willChangeValueForKey:kHeaderFields]; + + if (obj) { + [_headerFields setObject:obj forKey:key]; + } else { + [_headerFields removeObjectForKey:key]; + } + + [self didChangeValueForKey:kHeaderFields]; + +} + +- (NSDictionary *) queryParams { + + return [_queryParams copy]; + +} + +- (void) removeAllQueryParamValues { + + [self willChangeValueForKey:kQueryParams]; + [_queryParams removeAllObjects]; + [self didChangeValueForKey:kQueryParams]; + +} + +- (void) setValue:(id)obj forQueryParam:(NSString *)key { + + [self willChangeValueForKey:kQueryParams]; + + if (obj) { + [_queryParams setObject:obj forKey:key]; + } else { + [_queryParams removeObjectForKey:key]; + } + + [self didChangeValueForKey:kQueryParams]; + +} + +- (NSDictionary *) userInfo { + + return [_userInfo copy]; + +} + +- (void) removeAllUserInfoValues { + + [self willChangeValueForKey:kUserInfo]; + [_userInfo removeAllObjects]; + [self didChangeValueForKey:kUserInfo]; + +} + +- (void) setValue:(id)obj forUserInfo:(NSString *)key { + + [self willChangeValueForKey:kUserInfo]; + + if (obj) { + [_userInfo setObject:obj forKey:key]; + } else { + [_userInfo removeObjectForKey:key]; + } + + [self didChangeValueForKey:kUserInfo]; + +} + +@end diff --git a/IRWebAPIRequestOperation.h b/IRWebAPIRequestOperation.h new file mode 100644 index 0000000..d81411d --- /dev/null +++ b/IRWebAPIRequestOperation.h @@ -0,0 +1,32 @@ +// +// IRWebAPIRequestOperation.h +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import + +enum { + + IRWebAPIRequestStateEnqueued = 0, + IRWebAPIRequestStateRunning, + IRWebAPIRequestStateSucceeded, + IRWebAPIRequestStateFailed + +}; typedef NSUInteger IRWebAPIRequestState; + + +@class IRWebAPIRequestContext; +@interface IRWebAPIRequestOperation : NSOperation + +- (id) initWithContext:(IRWebAPIRequestContext *)context; + +@property (nonatomic, readonly, strong) IRWebAPIRequestContext *context; +@property (nonatomic, readonly, assign) IRWebAPIRequestState state; +@property (nonatomic, readonly, strong) NSURLRequest *request; +@property (nonatomic, readonly, strong) NSURLConnection *connection; +@property (nonatomic, readonly, strong) id result; + +@end diff --git a/IRWebAPIRequestOperation.m b/IRWebAPIRequestOperation.m new file mode 100644 index 0000000..092211e --- /dev/null +++ b/IRWebAPIRequestOperation.m @@ -0,0 +1,217 @@ +// +// IRWebAPIRequestOperation.m +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import "IRWebAPIRequestOperation.h" +#import "IRWebAPIRequestContext.h" +#import "IRWebAPIInterceptor.h" +#import "IRWebAPIHelpers.h" + +@interface IRWebAPIRequestOperation () { + BOOL _isExecuting; + BOOL _isFinished; +} +@property (nonatomic, readwrite, assign) IRWebAPIRequestState state; +@property (nonatomic, readwrite, strong) NSURLConnection *connection; +@property (nonatomic, readonly, strong) NSMutableData *data; +@property (nonatomic, readonly, strong) IRWebAPIInterceptor *interceptor; +@end + + +@implementation IRWebAPIRequestOperation +@synthesize context = _context; +@synthesize request = _request; +@synthesize connection = _connection; +@synthesize state = _state; +@synthesize result = _result; +@synthesize data = _data; +@synthesize interceptor = _interceptor; + +- (id) initWithContext:(IRWebAPIRequestContext *)context { + + NSLog(@"%s %@ %@", __PRETTY_FUNCTION__, context, context.baseURL); + + self = [super init]; + if (!self) + return; + + _context = context; + + _isExecuting = NO; + _isFinished = NO; + + _state = IRWebAPIRequestStateEnqueued; + + return self; + +} + +- (void) start { + + if (![NSThread isMainThread]) { + [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO]; + return; + } + + [self willChangeValueForKey:@"isExecuting"]; + _isExecuting = YES; + [self didChangeValueForKey:@"isExecuting"]; + + _data = [NSMutableData data]; + + _interceptor = [IRWebAPIInterceptor new]; + _interceptor.receiver = self; + + NSLog(@"self %@, interceptor %@", self, _interceptor); + + self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:(id)_interceptor]; + self.state = IRWebAPIRequestStateRunning; + + if (!_connection) { + self.state = IRWebAPIRequestStateFailed; + [self finish]; + } + +} + +- (void) cancel { + + [_connection cancel]; + _interceptor.receiver = nil; + + [super cancel]; + + self.state = IRWebAPIRequestStateFailed; + +// +// self.state = IRWebAPIRequestStateFailed; +// _connection = nil; +// +// [self willChangeValueForKey:@"isExecuting"]; +// _isExecuting = YES; +// [self didChangeValueForKey:@"isExecuting"]; +// +// [self willChangeValueForKey:@"isExecuting"]; +// _isExecuting = NO; +// [self didChangeValueForKey:@"isExecuting"]; +// +// [self willChangeValueForKey:@"isFinished"]; +// _isFinished = YES; +// [self didChangeValueForKey:@"isFinished"]; + +} + +- (void) finish { + + _connection = nil; + + if (self.data) + _result = self.context.parser(self.data); + + [self willChangeValueForKey:@"isExecuting"]; + [self willChangeValueForKey:@"isFinished"]; + + _isExecuting = NO; + _isFinished = YES; + + [self didChangeValueForKey:@"isExecuting"]; + [self didChangeValueForKey:@"isFinished"]; + +} + +- (BOOL) isExecuting { + + return _isExecuting; + +} + +- (BOOL) isFinished { + + return _isFinished; + +} + +- (NSURLRequest *) request { + + if (!_request) { + + NSURL *url = IRWebAPIRequestURLWithQueryParameters(self.context.baseURL, self.context.queryParams); + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:self.context.timeout]; + + [self.context.headerFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [request setValue:obj forHTTPHeaderField:key]; + }]; + + if (self.context.body) + [request setHTTPBody:self.context.body]; + + [request setHTTPMethod:self.context.method]; + [request setHTTPShouldHandleCookies:NO]; + + _request = request; + + } + + return _request; + +} + +- (void) connection:(NSURLConnection *)inConnection didReceiveData:(NSData *)inData { + + [self.data appendData:inData]; + +} + +- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { + + NSCParameterAssert([response isKindOfClass:[NSHTTPURLResponse class]]); + self.context.urlResponse = (NSHTTPURLResponse *)response; + + [self.data setLength:0]; + +} + +- (void) connectionDidFinishLoading:(NSURLConnection *)inConnection { + + self.state = IRWebAPIRequestStateSucceeded; + + [self finish]; + +} + +- (void) connection:(NSURLConnection *)inConnection didFailWithError:(NSError *)error { + + self.context.error = error; + self.state = IRWebAPIRequestStateFailed; + + [self finish]; + +} + +- (BOOL) connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { + + return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]; + +} + +- (void) connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { + + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) + if ([[self.context.baseURL host] isEqualToString:challenge.protectionSpace.host]) + [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; + + [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; + +} + +- (NSString *) description { + + return [NSString stringWithFormat:@"<%@: %p { %@ %@ %@ }>", NSStringFromClass([self class]), self, self.context.engineMethod, self.context.method, self.context.baseURL]; + +} + +@end diff --git a/IRWebAPIXOAuthAuthenticator.h b/IRWebAPIXOAuthAuthenticator.h index ab21e82..ba660e8 100644 --- a/IRWebAPIXOAuthAuthenticator.h +++ b/IRWebAPIXOAuthAuthenticator.h @@ -6,39 +6,13 @@ // Copyright 2010 Iridia Productions. All rights reserved. // -// OAUTH ON DESKTOP / MOBILE APPS IS A JOKE. -// THERE IS NO OAUTH AUTHENTICATOR PROVIDED. - @class IRWebAPIAuthenticator; -@interface IRWebAPIXOAuthAuthenticator : IRWebAPIAuthenticator { - - NSString *consumerKey; - NSString *consumerSecret; - - NSString *retrievedToken; - NSString *retrievedTokenSecret; - - NSURL *xAuthAccessTokenBaseURL; - NSURL *authorizeURL; - -} - -@property (nonatomic, readwrite, retain) NSString *consumerKey; -@property (nonatomic, readwrite, retain) NSString *consumerSecret; +@interface IRWebAPIXOAuthAuthenticator : IRWebAPIAuthenticator -@property (nonatomic, readwrite, retain) NSString *retrievedToken; -@property (nonatomic, readwrite, retain) NSString *retrievedTokenSecret; +@property (nonatomic, readwrite, copy) NSString *consumerKey; +@property (nonatomic, readwrite, copy) NSString *consumerSecret; - -- (NSDictionary *) oAuthHeaderValuesForHTTPMethod:(NSString *)inHTTPMethod baseURL:(NSURL *)inBaseURL arguments:(NSDictionary *)inMethodArguments; -- (NSString *) oAuthHeaderValueForHTTPMethod:(NSString *)inHTTPMethod baseURL:(NSURL *)inBaseURL arguments:(NSDictionary *)inMethodArguments; - -// The former returns a dictionary, which is used by the latter, which concatenates everything into a string ready for use in the Authorization header or another header, e.g. X-Verify-Credentials-Authorization - - -- (NSString *) oAuthHeaderValueForRequestContext:(NSDictionary *)inRequestContext; - -// Convenience. - +@property (nonatomic, readwrite, copy) NSString *retrievedToken; +@property (nonatomic, readwrite, copy) NSString *retrievedTokenSecret; @end diff --git a/IRWebAPIXOAuthAuthenticator.m b/IRWebAPIXOAuthAuthenticator.m index 51cbba4..ac5fe1c 100644 --- a/IRWebAPIXOAuthAuthenticator.m +++ b/IRWebAPIXOAuthAuthenticator.m @@ -7,6 +7,7 @@ // #import "IRWebAPIKit.h" +#import "IRWebAPIRequestContext.h" #import "IRWebAPIXOAuthAuthenticator.h" @@ -14,55 +15,67 @@ @interface IRWebAPIXOAuthAuthenticator () @property (nonatomic, retain, readwrite) IRWebAPICredentials *currentCredentials; +- (NSDictionary *) oAuthHeaderValuesForHTTPMethod:(NSString *)inHTTPMethod baseURL:(NSURL *)inBaseURL arguments:(NSDictionary *)inMethodArguments; +- (NSString *) oAuthHeaderValueForHTTPMethod:(NSString *)inHTTPMethod baseURL:(NSURL *)inBaseURL arguments:(NSDictionary *)inMethodArguments; + +// The former returns a dictionary, which is used by the latter, which concatenates everything into a string ready for use in the Authorization header or another header, e.g. X-Verify-Credentials-Authorization + + +- (NSString *) oAuthHeaderValueForRequestContext:(IRWebAPIRequestContext *)inRequestContext; + +// Convenience. + @end @implementation IRWebAPIXOAuthAuthenticator -@synthesize consumerKey, consumerSecret, retrievedToken, retrievedTokenSecret; -@synthesize currentCredentials; +@synthesize consumerKey = _consumerKey; +@synthesize consumerSecret = _consumerSecret; +@synthesize retrievedToken = _retrievedToken; +@synthesize retrievedTokenSecret = _retrievedTokenSecret; +@synthesize currentCredentials = _currentCredentials; - (void) createTransformerBlocks { __weak IRWebAPIXOAuthAuthenticator *wSelf = self; - self.globalRequestPostTransformerBlock = ^ (NSDictionary *inOriginalContext) { + self.globalRequestPostTransformerBlock = ^ (IRWebAPIRequestContext *context) { - NSMutableDictionary *mutatedContext = [inOriginalContext mutableCopy]; - NSMutableDictionary *mutatedContextHeaderFields = (NSMutableDictionary *)[mutatedContext objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - - BOOL isRequestAuthenticated = (BOOL)(!!(self.retrievedTokenSecret)), - isPOST = [@"POST" isEqual:[mutatedContext valueForKey:kIRWebAPIEngineRequestHTTPMethod]], + BOOL isRequestAuthenticated = (BOOL)(!!(self.retrievedTokenSecret)), + isPOST = [@"POST" isEqual:context.method], removesQueryParameters = NO; - + if (isRequestAuthenticated && isPOST) { - [mutatedContext setObject:((^ { + [context setBody:((^ { NSMutableArray *POSTBodyElements = [NSMutableArray array]; - [[mutatedContext objectForKey:kIRWebAPIEngineRequestHTTPQueryParameters] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [context.queryParams enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { [POSTBodyElements addObject:[NSString stringWithFormat:@"%@=%@", key, IRWebAPIKitRFC3986EncodedStringMake(obj)]]; }]; - + return [[POSTBodyElements componentsJoinedByString:@"&"] dataUsingEncoding:NSUTF8StringEncoding]; - })()) forKey:kIRWebAPIEngineRequestHTTPBody]; + })())]; - [mutatedContextHeaderFields setObject:@"application/x-www-form-urlencoded" forKey:@"Content-Type"]; + [context setValue:@"application/x-www-form-urlencoded" forHeaderField:@"Content-Type"]; removesQueryParameters = YES; } - [mutatedContextHeaderFields setObject:[wSelf oAuthHeaderValueForRequestContext:mutatedContext] forKey:@"Authorization"]; + id authHeaderFieldValue = [wSelf oAuthHeaderValueForRequestContext:context]; - if (removesQueryParameters) - [mutatedContext setObject:[NSMutableArray array] forKey:kIRWebAPIEngineRequestHTTPQueryParameters]; + [context setValue:authHeaderFieldValue forHeaderField:@"Authorization"]; - return mutatedContext; + if (removesQueryParameters) + [context removeAllQueryParamValues]; + + return context; }; @@ -80,30 +93,25 @@ - (void) associateWithEngine:(IRWebAPIEngine *)inEngine { } - (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess:(IRWebAPIAuthenticatorCallback)successHandler onFailure:(IRWebAPIAuthenticatorCallback)failureHandler { - - [self.engine fireAPIRequestNamed:@"oauth/access_token" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: + + IRWebAPIRequestOperation *operation = [self.engine operationForMethod:@"oauth/access_token" arguments:[NSDictionary dictionaryWithObjectsAndKeys: inCredentials.identifier, @"x_auth_username", inCredentials.qualifier, @"x_auth_password", @"client_auth", @"x_auth_mode", - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: + nil] validator: ^ (NSDictionary *response, IRWebAPIRequestContext *context) { - IRWebAPIResponseQueryResponseParserMake(), kIRWebAPIEngineParser, - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator: ^ (NSDictionary *inResponseOrNil, NSDictionary *inRequestContext) { - - if (!([IRWebAPIInterface defaultNoErrorValidator])(inResponseOrNil, inRequestContext)) + if (!([IRWebAPIInterface defaultNoErrorValidator])(response, context)) return NO; for (id key in [NSArray arrayWithObjects:@"oauth_token", @"oauth_token_secret", nil]) - if (!IRWebAPIKitValidResponse([inResponseOrNil objectForKey:key])) - return NO; + if (!IRWebAPIKitValidResponse([response objectForKey:key])) + return NO; return YES; - } successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { + } successBlock: ^ (NSDictionary *inResponseOrNil, IRWebAPIRequestContext *context) { self.retrievedToken = [inResponseOrNil valueForKey:@"oauth_token"]; self.retrievedTokenSecret = [inResponseOrNil valueForKey:@"oauth_token_secret"]; @@ -117,21 +125,24 @@ - (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess: NSParameterAssert(self.currentCredentials && self.currentCredentials.authenticated); if (successHandler) - successHandler(self, YES, outShouldRetry); + successHandler(self, YES); - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { + } failureBlock: ^ (NSDictionary *inResponseOrNil, IRWebAPIRequestContext *context) { self.currentCredentials.authenticated = NO; self.retrievedToken = nil; self.retrievedTokenSecret = nil; - NSLog(@"XOAuth FAIL %@, %@", inResponseOrNil, inResponseContext); - if (failureHandler) - failureHandler(self, NO, outShouldRetry); + failureHandler(self, NO); }]; - + + operation.context.parser = IRWebAPIResponseQueryResponseParserMake(); + operation.context.method = @"POST"; + + [operation start]; + } @@ -204,9 +215,13 @@ - (NSString *) oAuthHeaderValueForHTTPMethod:(NSString *)inHTTPMethod baseURL:(N } -- (NSString *) oAuthHeaderValueForRequestContext:(NSDictionary *)inRequestContext { +- (NSString *) oAuthHeaderValueForRequestContext:(IRWebAPIRequestContext *)context { + + NSString *method = context.method; + NSURL *baseURL = context.baseURL; + NSDictionary *arguments = context.queryParams; - return [self oAuthHeaderValueForHTTPMethod:[inRequestContext valueForKey:kIRWebAPIEngineRequestHTTPMethod] baseURL:[inRequestContext valueForKey:kIRWebAPIEngineRequestHTTPBaseURL] arguments:[inRequestContext valueForKey:kIRWebAPIEngineRequestHTTPQueryParameters]]; + return [self oAuthHeaderValueForHTTPMethod:method baseURL:baseURL arguments:arguments]; } From 9030bb03ed8c5b3109a0dd594258f95e985c9d15 Mon Sep 17 00:00:00 2001 From: Evadne Wu Date: Wed, 27 Jun 2012 14:41:28 +0800 Subject: [PATCH 09/32] appends fixes --- IRWebAPIEngine+ExternalTransforms.m | 8 ++++---- IRWebAPIEngine.m | 2 +- IRWebAPIRequestOperation.m | 12 +++++++----- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/IRWebAPIEngine+ExternalTransforms.m b/IRWebAPIEngine+ExternalTransforms.m index 3535097..5aa1fc7 100644 --- a/IRWebAPIEngine+ExternalTransforms.m +++ b/IRWebAPIEngine+ExternalTransforms.m @@ -12,11 +12,9 @@ @interface IRWebAPIEngine (ExternalTransforms_KnownPrivate) -- (IRWebAPIRequestContext *) baseRequestContextWithMethodName:(NSString *)inMethodName arguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil; - - (IRWebAPIRequestContext *) requestContextByTransformingContext:(IRWebAPIRequestContext *)inContext forMethodNamed:(NSString *)inMethodName; -- (NSURLRequest *) requestWithContext:(IRWebAPIRequestContext *)inContext; +//- (NSURLRequest *) requestWithContext:(IRWebAPIRequestContext *)inContext; @end @@ -24,7 +22,9 @@ @implementation IRWebAPIEngine (ExternalTransforms) - (NSURLRequest *) transformedRequestWithRequest:(NSURLRequest *)aRequest usingMethodName:(NSString *)aName { - IRWebAPIRequestContext *baseContext = [self baseRequestContextWithMethodName:aName arguments:nil options:nil]; + IRWebAPIRequestContext *baseContext = [IRWebAPIRequestContext new]; + baseContext.baseURL = [self.context baseURLForMethodNamed:aName]; + baseContext.engineMethod = aName; NSURL *baseURL = baseContext.baseURL; NSDictionary *headerFields = baseContext.headerFields; diff --git a/IRWebAPIEngine.m b/IRWebAPIEngine.m index a708b27..22088e3 100644 --- a/IRWebAPIEngine.m +++ b/IRWebAPIEngine.m @@ -96,7 +96,7 @@ - (IRWebAPIRequestOperation *) operationForMethod:(NSString *)method arguments:( __weak IRWebAPIRequestOperation *wOperation = operation; [operation setCompletionBlock:^{ - + IRWebAPIRequestState state = wOperation.state; IRWebAPIRequestContext *context = wOperation.context; NSDictionary *response = (NSDictionary *)wOperation.result; diff --git a/IRWebAPIRequestOperation.m b/IRWebAPIRequestOperation.m index 092211e..0285fe3 100644 --- a/IRWebAPIRequestOperation.m +++ b/IRWebAPIRequestOperation.m @@ -33,8 +33,6 @@ @implementation IRWebAPIRequestOperation - (id) initWithContext:(IRWebAPIRequestContext *)context { - NSLog(@"%s %@ %@", __PRETTY_FUNCTION__, context, context.baseURL); - self = [super init]; if (!self) return; @@ -66,8 +64,6 @@ - (void) start { _interceptor = [IRWebAPIInterceptor new]; _interceptor.receiver = self; - NSLog(@"self %@, interceptor %@", self, _interceptor); - self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:(id)_interceptor]; self.state = IRWebAPIRequestStateRunning; @@ -86,7 +82,13 @@ - (void) cancel { [super cancel]; self.state = IRWebAPIRequestStateFailed; - + + if ([self.context.engineMethod hasSuffix:@"upload"]) { + + NSLog(@"gg"); + + } + // // self.state = IRWebAPIRequestStateFailed; // _connection = nil; From 973e7e4dabdff8fbbcaa2d9ecea004503fc776c3 Mon Sep 17 00:00:00 2001 From: Evadne Wu Date: Wed, 27 Jun 2012 15:04:55 +0800 Subject: [PATCH 10/32] removes superfluous code --- IRWebAPIRequestOperation.m | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/IRWebAPIRequestOperation.m b/IRWebAPIRequestOperation.m index 0285fe3..95cd873 100644 --- a/IRWebAPIRequestOperation.m +++ b/IRWebAPIRequestOperation.m @@ -83,28 +83,6 @@ - (void) cancel { self.state = IRWebAPIRequestStateFailed; - if ([self.context.engineMethod hasSuffix:@"upload"]) { - - NSLog(@"gg"); - - } - -// -// self.state = IRWebAPIRequestStateFailed; -// _connection = nil; -// -// [self willChangeValueForKey:@"isExecuting"]; -// _isExecuting = YES; -// [self didChangeValueForKey:@"isExecuting"]; -// -// [self willChangeValueForKey:@"isExecuting"]; -// _isExecuting = NO; -// [self didChangeValueForKey:@"isExecuting"]; -// -// [self willChangeValueForKey:@"isFinished"]; -// _isFinished = YES; -// [self didChangeValueForKey:@"isFinished"]; - } - (void) finish { From 4ae1713b87733b1655a916409a8ed2e2a9ffab03 Mon Sep 17 00:00:00 2001 From: Evadne Wu Date: Wed, 27 Jun 2012 15:09:04 +0800 Subject: [PATCH 11/32] fixes engineMethod not copied during transformation --- IRWebAPIEngine+ExternalTransforms.m | 1 + 1 file changed, 1 insertion(+) diff --git a/IRWebAPIEngine+ExternalTransforms.m b/IRWebAPIEngine+ExternalTransforms.m index 5aa1fc7..f8b5987 100644 --- a/IRWebAPIEngine+ExternalTransforms.m +++ b/IRWebAPIEngine+ExternalTransforms.m @@ -63,6 +63,7 @@ - (NSURLRequest *) transformedRequestWithRequest:(NSURLRequest *)aRequest usingM IRWebAPIRequestContext *inferredContext = [IRWebAPIRequestContext new]; inferredContext.baseURL = baseURL; + inferredContext.engineMethod = baseContext.engineMethod; [headerFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { [inferredContext setValue:obj forHeaderField:key]; }]; From 119b2ce547aa975cbdfd2931678e6150e89d8cd9 Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Wed, 27 Jun 2012 16:07:07 +0800 Subject: [PATCH 12/32] resolves several threading issues - fixes bad exception handling by explicitly trapping them from the background queue instead of doing it on the main queue - fixes POST form multipart options not being transformed into the operation configuration override process --- IRWebAPIEngine+OperationFiring.m | 4 ++++ IRWebAPIEngine.m | 38 ++++++++++++++++++-------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/IRWebAPIEngine+OperationFiring.m b/IRWebAPIEngine+OperationFiring.m index 93b50f6..f0a09ad 100644 --- a/IRWebAPIEngine+OperationFiring.m +++ b/IRWebAPIEngine+OperationFiring.m @@ -60,6 +60,10 @@ - (void) fireAPIRequestNamed:(NSString *)methodName withArguments:(NSDictionary [context setValue:obj forFormURLEncodingField:key]; }]; + [[options objectForKey:kIRWebAPIEngineRequestContextFormMultipartFieldsKey] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [context setValue:obj forFormMultipartField:key]; + }]; + } validator:validatorBlock successBlock:successBlock failureBlock:failureBlock]; [self.queue addOperation:operation]; diff --git a/IRWebAPIEngine.m b/IRWebAPIEngine.m index 22088e3..058d3a0 100644 --- a/IRWebAPIEngine.m +++ b/IRWebAPIEngine.m @@ -100,38 +100,42 @@ - (IRWebAPIRequestOperation *) operationForMethod:(NSString *)method arguments:( IRWebAPIRequestState state = wOperation.state; IRWebAPIRequestContext *context = wOperation.context; NSDictionary *response = (NSDictionary *)wOperation.result; - - dispatch_async(dispatch_get_main_queue(), ^{ - - NSCParameterAssert((state == IRWebAPIRequestStateSucceeded) || (state == IRWebAPIRequestStateFailed)); - - NSCParameterAssert(!response || [response isKindOfClass:[NSDictionary class]]); + + @try { + NSCParameterAssert((state == IRWebAPIRequestStateSucceeded) || (state == IRWebAPIRequestStateFailed)); + NSCParameterAssert(!response || [response isKindOfClass:[NSDictionary class]]); + NSDictionary *transformedResponse = [wSelf responseByTransformingResponse:response withRequestContext:context forMethodNamed:method]; if (state == IRWebAPIRequestStateSucceeded) { - + if ((validator != nil) && (!validator(transformedResponse, context))) { - + if (failureBlock) failureBlock(transformedResponse, context); - + } else { - + if (successBlock) successBlock(transformedResponse, context); - + } - + } else { - + if (failureBlock) failureBlock(transformedResponse, context); - + } - - }); - + + } @catch (NSException *exception) { + + if (failureBlock) + failureBlock(nil, context); + + } + }]; return operation; From edf78e29841887b600a8983f050edb33ebf3d6ff Mon Sep 17 00:00:00 2001 From: Evadne Wu Date: Wed, 27 Jun 2012 16:45:16 +0800 Subject: [PATCH 13/32] OS X target fixed --- IRRemoteResourcesManager.m | 2 +- IRWebAPIKit.xcodeproj/project.pbxproj | 10 ++++++++++ IRWebAPIRequestOperation.m | 2 +- IRWebAPIResponseParser.m | 4 +--- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/IRRemoteResourcesManager.m b/IRRemoteResourcesManager.m index 92dc3f4..4c68789 100644 --- a/IRRemoteResourcesManager.m +++ b/IRRemoteResourcesManager.m @@ -290,7 +290,7 @@ - (IRRemoteResourceDownloadOperation *) prospectiveOperationForURL:(NSURL *)anUR } completion: ^ { BOOL didFinish = !!(operation.path); - NSString *operationPath = operation.path; + // NSString *operationPath = operation.path; NSURL *operationURL = operation.url; if (didFinish) { diff --git a/IRWebAPIKit.xcodeproj/project.pbxproj b/IRWebAPIKit.xcodeproj/project.pbxproj index 5df6cca..0d8674a 100644 --- a/IRWebAPIKit.xcodeproj/project.pbxproj +++ b/IRWebAPIKit.xcodeproj/project.pbxproj @@ -84,6 +84,11 @@ FFBEE72F15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.m in Sources */ = {isa = PBXBuildFile; fileRef = FFBEE72D15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.m */; }; FFDB8EFD15943C7800FA7E9B /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFDB8EFC15943C7800FA7E9B /* MobileCoreServices.framework */; }; FFDB8EFE15943C8100FA7E9B /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFDB8EFC15943C7800FA7E9B /* MobileCoreServices.framework */; }; + FFDE51EC159AEF870086F9B0 /* IRWebAPIRequestContext.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9838A21598313D00CFF2DF /* IRWebAPIRequestContext.m */; }; + FFDE51EE159AEF940086F9B0 /* IRWebAPIRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9838A715984A4A00CFF2DF /* IRWebAPIRequestOperation.m */; }; + FFDE51EF159AEFA90086F9B0 /* IRWebAPIInterceptor.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9838AB1598502B00CFF2DF /* IRWebAPIInterceptor.m */; }; + FFDE51FF159AF8F10086F9B0 /* IRWebAPIEngine+FormMultipart.h in Headers */ = {isa = PBXBuildFile; fileRef = FF9AFB7112EC5C060037E930 /* IRWebAPIEngine+FormMultipart.h */; }; + FFDE5200159AF9030086F9B0 /* IRWebAPIEngine+OperationFiring.m in Sources */ = {isa = PBXBuildFile; fileRef = FFBEE72D15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.m */; }; FFF5AC741470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h in Headers */ = {isa = PBXBuildFile; fileRef = FFF5AC721470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h */; }; FFF5AC751470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF5AC731470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m */; }; /* End PBXBuildFile section */ @@ -383,6 +388,7 @@ buildActionMask = 2147483647; files = ( FF460DB4149CFF3F00DB7F0B /* IRRemoteResourceDownloadOperation.h in Headers */, + FFDE51FF159AF8F10086F9B0 /* IRWebAPIEngine+FormMultipart.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -572,6 +578,10 @@ FF59A3BE1441C9F400BB1FDC /* IRWebAPIInterface+Validators.m in Sources */, FF460D07149CF80600DB7F0B /* IRWebAPIEngine+FormURLEncoding.m in Sources */, FF460D09149CF80B00DB7F0B /* IRWebAPIEngine+ExternalTransforms.m in Sources */, + FFDE51EC159AEF870086F9B0 /* IRWebAPIRequestContext.m in Sources */, + FFDE51EE159AEF940086F9B0 /* IRWebAPIRequestOperation.m in Sources */, + FFDE51EF159AEFA90086F9B0 /* IRWebAPIInterceptor.m in Sources */, + FFDE5200159AF9030086F9B0 /* IRWebAPIEngine+OperationFiring.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/IRWebAPIRequestOperation.m b/IRWebAPIRequestOperation.m index 95cd873..b700659 100644 --- a/IRWebAPIRequestOperation.m +++ b/IRWebAPIRequestOperation.m @@ -35,7 +35,7 @@ - (id) initWithContext:(IRWebAPIRequestContext *)context { self = [super init]; if (!self) - return; + return nil; _context = context; diff --git a/IRWebAPIResponseParser.m b/IRWebAPIResponseParser.m index cf1631b..491f55f 100644 --- a/IRWebAPIResponseParser.m +++ b/IRWebAPIResponseParser.m @@ -8,9 +8,7 @@ #import "IRWebAPIResponseParser.h" - - - +NSDictionary * IRWebAPIResponseDictionarize (id incomingObject); NSDictionary * IRWebAPIResponseDictionarize (id incomingObject) { From 2fac3aa726ca16a53d9a406517b70e93e54da4db Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Fri, 3 Aug 2012 02:33:05 +0800 Subject: [PATCH 14/32] delay download operation removal --- IRRemoteResourcesManager.m | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/IRRemoteResourcesManager.m b/IRRemoteResourcesManager.m index 41c1003..b6ca618 100644 --- a/IRRemoteResourcesManager.m +++ b/IRRemoteResourcesManager.m @@ -402,9 +402,6 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri operation.queuePriority = priority; [nrSelf addOperation:operation]; - [operation appendCompletionBlock:^{ - [nrSelf removeOperation:operation]; - }]; } else { @@ -414,9 +411,6 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri operation.queuePriority = priority; [nrSelf addOperation:operation]; - [operation appendCompletionBlock:^{ - [nrSelf removeOperation:operation]; - }]; } @@ -448,6 +442,16 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri }]; } + + [operation appendCompletionBlock:^{ + + double delayInSeconds = 2.0; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + [nrSelf removeOperation:operation]; + }); + + }]; dispatch_async(dispatch_get_main_queue(), ^{ From 6445bd03ba8377fb173dd570069a4565b7eb7f73 Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Thu, 9 Aug 2012 20:53:40 +0800 Subject: [PATCH 15/32] fix deprecated functions --- IRWebAPIEngine+FormMultipart.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IRWebAPIEngine+FormMultipart.m b/IRWebAPIEngine+FormMultipart.m index fb01a5a..fe3d56c 100644 --- a/IRWebAPIEngine+FormMultipart.m +++ b/IRWebAPIEngine+FormMultipart.m @@ -158,7 +158,7 @@ + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { [fileHandle writeData:newLineData]; [fileHandle writeData:newLineData]; - [fileHandle writeData:[NSData dataWithContentsOfMappedFile:[(NSURL *)incomingObject path]]]; + [fileHandle writeData:[NSData dataWithContentsOfFile:[(NSURL *)incomingObject path] options:NSDataReadingMappedIfSafe error:nil]]; } else if ([incomingObject isKindOfClass:[NSData class]]) { @@ -182,7 +182,7 @@ + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { [fileHandle closeFile]; - [context setBody:[NSData dataWithContentsOfMappedFile:[fileHandleURL path]]]; + [context setBody:[NSData dataWithContentsOfFile:[fileHandleURL path] options:NSDataReadingMappedIfSafe error:nil]]; [context addCacheFileURL:fileHandleURL]; [context removeAllFormMultipartFieldValues]; [context setMethod:@"POST"]; From dfea028742b05e9c96db33f054140627c997b5ee Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Tue, 14 Aug 2012 18:26:05 +0800 Subject: [PATCH 16/32] add error handling for failure download operations --- IRRemoteResourcesManager.m | 40 ++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/IRRemoteResourcesManager.m b/IRRemoteResourcesManager.m index 48a1e6f..eff2374 100644 --- a/IRRemoteResourcesManager.m +++ b/IRRemoteResourcesManager.m @@ -402,7 +402,13 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri [wSelf addOperation:operation]; - } + } else if ([operation isCancelled]) { + + [wSelf removeOperation:operation]; + operation = [wSelf prospectiveOperationForURL:anURL enqueue:YES]; + operation.queuePriority = priority; + [wSelf addOperation:operation]; + } } @@ -415,7 +421,10 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri if (![[NSFileManager defaultManager] fileExistsAtPath:capturedPath]) { [wSelf performInBackground:^{ - aBlock(nil); + + [wSelf removeOperation:operation]; + aBlock(nil); + }]; return; @@ -426,6 +435,11 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri NSCParameterAssert([[NSFileManager defaultManager] fileExistsAtPath:capturedPath]); aBlock([NSURL fileURLWithPath:capturedPath]); + double delayInSeconds = 2.0; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + [wSelf removeOperation:operation]; + }); }]; @@ -433,16 +447,6 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri } - [operation appendCompletionBlock:^{ - - double delayInSeconds = 2.0; - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - [wSelf removeOperation:operation]; - }); - - }]; - dispatch_async(dispatch_get_main_queue(), ^{ [self beginSuspendingOperationQueue]; @@ -521,9 +525,15 @@ - (void) enqueueOperationsIfNeeded { return (BOOL)![legitimateOperations containsObject:evaluatedObject]; }); - for (NSOperation *anOperation in insertedOperations) - if (![self.queue.operations containsObject:anOperation]) - [self.queue addOperation:anOperation]; + for (IRRemoteResourceDownloadOperation *anOperation in insertedOperations) { + if (![self.queue.operations containsObject:anOperation]) { + // sometimes the delegate will be nil, so add a workaround here + if (!anOperation.delegate) { + anOperation.delegate = self; + } + [self.queue addOperation:anOperation]; + } + } [self.enqueuedOperations removeObjectsInArray:insertedOperations]; From 608f235e3b957549822539af40dcae26bbcae38a Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Tue, 14 Aug 2012 21:43:11 +0800 Subject: [PATCH 17/32] canceled operation will be re-enqueue automatically, so we don't need to do it again --- IRRemoteResourcesManager.m | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/IRRemoteResourcesManager.m b/IRRemoteResourcesManager.m index eff2374..bee94b8 100644 --- a/IRRemoteResourcesManager.m +++ b/IRRemoteResourcesManager.m @@ -402,13 +402,14 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri [wSelf addOperation:operation]; - } else if ([operation isCancelled]) { - - [wSelf removeOperation:operation]; - operation = [wSelf prospectiveOperationForURL:anURL enqueue:YES]; - operation.queuePriority = priority; - [wSelf addOperation:operation]; - } + } +// else if ([operation isCancelled]) { +// +// [wSelf removeOperation:operation]; +// operation = [wSelf prospectiveOperationForURL:anURL enqueue:YES]; +// operation.queuePriority = priority; +// [wSelf addOperation:operation]; +// } } From f5148d2b7b7ce5a5aa05694df514d5f677760841 Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Wed, 15 Aug 2012 12:37:37 +0800 Subject: [PATCH 18/32] DO NOT add completion block to old operations --- IRRemoteResourcesManager.m | 135 +++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 67 deletions(-) diff --git a/IRRemoteResourcesManager.m b/IRRemoteResourcesManager.m index bee94b8..7701365 100644 --- a/IRRemoteResourcesManager.m +++ b/IRRemoteResourcesManager.m @@ -384,6 +384,7 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri [wSelf performInBackground: ^ { + BOOL isNewOperation = NO; IRRemoteResourceDownloadOperation *operation = [wSelf operationWithURL:anURL]; if (!operation) { @@ -392,6 +393,8 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri operation.queuePriority = priority; [wSelf addOperation:operation]; + + isNewOperation = YES; } else { @@ -402,79 +405,77 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri [wSelf addOperation:operation]; + isNewOperation = YES; } -// else if ([operation isCancelled]) { -// -// [wSelf removeOperation:operation]; -// operation = [wSelf prospectiveOperationForURL:anURL enqueue:YES]; -// operation.queuePriority = priority; -// [wSelf addOperation:operation]; -// } } - if (aBlock) { - - [operation appendCompletionBlock: ^ { - - NSString *capturedPath = operation.path; - - if (![[NSFileManager defaultManager] fileExistsAtPath:capturedPath]) { - - [wSelf performInBackground:^{ + if (isNewOperation) { - [wSelf removeOperation:operation]; - aBlock(nil); + if (aBlock) { - }]; - - return; - - } - - [wSelf performInBackground: ^ { - - NSCParameterAssert([[NSFileManager defaultManager] fileExistsAtPath:capturedPath]); - aBlock([NSURL fileURLWithPath:capturedPath]); - double delayInSeconds = 2.0; - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - [wSelf removeOperation:operation]; - }); - - }]; - - }]; - - } - - dispatch_async(dispatch_get_main_queue(), ^{ + [operation appendCompletionBlock: ^ { - [self beginSuspendingOperationQueue]; - - [wSelf performInBackground: ^ { - - [self enqueueOperationsIfNeeded]; - - if ([self.enqueuedOperations containsObject:operation]) { - - // Hoist it — This is last come, first serve - - [self.enqueuedOperations removeObject:operation]; - [self.enqueuedOperations insertObject:operation atIndex:0]; - - } - - dispatch_async(dispatch_get_main_queue(), ^{ + NSString *capturedPath = operation.path; - [self endSuspendingOperationQueue]; - - }); + if (![[NSFileManager defaultManager] fileExistsAtPath:capturedPath]) { + + [wSelf performInBackground:^{ + + [wSelf removeOperation:operation]; + aBlock(nil); + + }]; + + return; + + } + + [wSelf performInBackground: ^ { + + NSCParameterAssert([[NSFileManager defaultManager] fileExistsAtPath:capturedPath]); + aBlock([NSURL fileURLWithPath:capturedPath]); + double delayInSeconds = 2.0; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + [wSelf removeOperation:operation]; + }); + + }]; + + }]; + + } + + } + + dispatch_async(dispatch_get_main_queue(), ^{ + + [self beginSuspendingOperationQueue]; + + [wSelf performInBackground: ^ { + + [self enqueueOperationsIfNeeded]; + + if ([self.enqueuedOperations containsObject:operation]) { + + // Hoist it — This is last come, first serve + + [self.enqueuedOperations removeObject:operation]; + [self.enqueuedOperations insertObject:operation atIndex:0]; + + } + + dispatch_async(dispatch_get_main_queue(), ^{ + + [self endSuspendingOperationQueue]; + + }); + + }]; + + }); - }]; - - }); - }]; } @@ -526,7 +527,7 @@ - (void) enqueueOperationsIfNeeded { return (BOOL)![legitimateOperations containsObject:evaluatedObject]; }); - for (IRRemoteResourceDownloadOperation *anOperation in insertedOperations) { + for (IRRemoteResourceDownloadOperation *anOperation in insertedOperations) { if (![self.queue.operations containsObject:anOperation]) { // sometimes the delegate will be nil, so add a workaround here if (!anOperation.delegate) { @@ -535,8 +536,8 @@ - (void) enqueueOperationsIfNeeded { [self.queue addOperation:anOperation]; } } - - [self.enqueuedOperations removeObjectsInArray:insertedOperations]; + + [self.enqueuedOperations removeObjectsInArray:insertedOperations]; [postponedOperations enumerateObjectsUsingBlock: ^ (IRRemoteResourceDownloadOperation *anOperation, NSUInteger idx, BOOL *stop) { [self.enqueuedOperations addObject:[anOperation continuationOperationCancellingCurrentOperation:YES]]; From 5f676bef5370d7b5dfa12e413340a241d24c37c9 Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Thu, 16 Aug 2012 10:18:58 +0800 Subject: [PATCH 19/32] 1. Remove LIFO optimization for existing download operations to reduce CPU time. 2. Cancelation of current download operations are buggy, mark them out --- IRRemoteResourcesManager.m | 83 ++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/IRRemoteResourcesManager.m b/IRRemoteResourcesManager.m index 7701365..49ee7de 100644 --- a/IRRemoteResourcesManager.m +++ b/IRRemoteResourcesManager.m @@ -339,8 +339,8 @@ - (IRRemoteResourceDownloadOperation *) prospectiveOperationForURL:(NSURL *)anUR operation.delegate = self; - if (enqueuesOperation) - [self.enqueuedOperations insertObject:operation atIndex:0]; +// if (enqueuesOperation) +// [self.enqueuedOperations insertObject:operation atIndex:0]; return operation; @@ -408,6 +408,10 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri isNewOperation = YES; } + if (priority > operation.queuePriority) { + operation.queuePriority = priority; + } + } if (isNewOperation) { @@ -447,34 +451,45 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri } - } - - dispatch_async(dispatch_get_main_queue(), ^{ - - [self beginSuspendingOperationQueue]; - - [wSelf performInBackground: ^ { - - [self enqueueOperationsIfNeeded]; - - if ([self.enqueuedOperations containsObject:operation]) { - - // Hoist it — This is last come, first serve - - [self.enqueuedOperations removeObject:operation]; - [self.enqueuedOperations insertObject:operation atIndex:0]; - - } - - dispatch_async(dispatch_get_main_queue(), ^{ - - [self endSuspendingOperationQueue]; - - }); + dispatch_sync(dispatch_get_main_queue(), ^{ + [self beginSuspendingOperationQueue]; + }); + + [self.enqueuedOperations insertObject:operation atIndex:0]; + [self enqueueOperationsIfNeeded]; + + dispatch_sync(dispatch_get_main_queue(), ^{ + [self endSuspendingOperationQueue]; + }); - }]; + } - }); +// dispatch_async(dispatch_get_main_queue(), ^{ +// +// [self beginSuspendingOperationQueue]; +// +// [wSelf performInBackground: ^ { +// +// if ([self.enqueuedOperations containsObject:operation]) { +// +// // Hoist it — This is last come, first serve +// +// [self.enqueuedOperations removeObject:operation]; +// [self.enqueuedOperations insertObject:operation atIndex:0]; +// +// } +// +// [self enqueueOperationsIfNeeded]; +// +// dispatch_async(dispatch_get_main_queue(), ^{ +// +// [self endSuspendingOperationQueue]; +// +// }); +// +// }]; +// +// }); }]; @@ -523,9 +538,9 @@ - (void) enqueueOperationsIfNeeded { return (BOOL)![sortedCurrentOperations containsObject:evaluatedObject]; }); - NSArray *postponedOperations = filtered(sortedCurrentOperations, ^ (id evaluatedObject, NSDictionary *bindings) { - return (BOOL)![legitimateOperations containsObject:evaluatedObject]; - }); +// NSArray *postponedOperations = filtered(sortedCurrentOperations, ^ (id evaluatedObject, NSDictionary *bindings) { +// return (BOOL)![legitimateOperations containsObject:evaluatedObject]; +// }); for (IRRemoteResourceDownloadOperation *anOperation in insertedOperations) { if (![self.queue.operations containsObject:anOperation]) { @@ -539,9 +554,9 @@ - (void) enqueueOperationsIfNeeded { [self.enqueuedOperations removeObjectsInArray:insertedOperations]; - [postponedOperations enumerateObjectsUsingBlock: ^ (IRRemoteResourceDownloadOperation *anOperation, NSUInteger idx, BOOL *stop) { - [self.enqueuedOperations addObject:[anOperation continuationOperationCancellingCurrentOperation:YES]]; - }]; +// [postponedOperations enumerateObjectsUsingBlock: ^ (IRRemoteResourceDownloadOperation *anOperation, NSUInteger idx, BOOL *stop) { +// [self.enqueuedOperations addObject:[anOperation continuationOperationCancellingCurrentOperation:YES]]; +// }]; } From c8a056238114605ea9573d8145a1ac6786bc4d0e Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Mon, 20 Aug 2012 15:37:30 +0800 Subject: [PATCH 20/32] Replace native JSON parser with 3rd-party library JSONKit --- IRWebAPIKit.xcodeproj/project.pbxproj | 4 + IRWebAPIResponseParser.m | 10 +- JSONKit.h | 251 ++++++++++++++++++++++++++ 3 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 JSONKit.h diff --git a/IRWebAPIKit.xcodeproj/project.pbxproj b/IRWebAPIKit.xcodeproj/project.pbxproj index 0d8674a..0239bea 100644 --- a/IRWebAPIKit.xcodeproj/project.pbxproj +++ b/IRWebAPIKit.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 130EFA1115E2205400254163 /* JSONKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 130EFA1015E2205400254163 /* JSONKit.h */; }; FF0D4C0B12ED96E500D9B97D /* IRWebAPIHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = FF0D4C0A12ED96E500D9B97D /* IRWebAPIHelpers.m */; }; FF0E874112B9F41C00DF571E /* IRWebAPIInterfaceURLShortening.h in Headers */ = {isa = PBXBuildFile; fileRef = FF0E874012B9F41C00DF571E /* IRWebAPIInterfaceURLShortening.h */; }; FF0E93E9132BB07000A316E1 /* IRRemoteResourcesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = FF0E93E7132BB07000A316E1 /* IRRemoteResourcesManager.h */; }; @@ -104,6 +105,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 130EFA1015E2205400254163 /* JSONKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONKit.h; sourceTree = ""; }; FF0D4C0A12ED96E500D9B97D /* IRWebAPIHelpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIHelpers.m; sourceTree = ""; }; FF0E874012B9F41C00DF571E /* IRWebAPIInterfaceURLShortening.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIInterfaceURLShortening.h; sourceTree = ""; }; FF0E93E7132BB07000A316E1 /* IRRemoteResourcesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRRemoteResourcesManager.h; sourceTree = ""; }; @@ -328,6 +330,7 @@ FF74080C1296A88400571D46 = { isa = PBXGroup; children = ( + 130EFA1015E2205400254163 /* JSONKit.h */, FF9AFB4B12EC597C0037E930 /* IRWebAPIKitDefines.h */, FF9AFB7F12EC5CB80037E930 /* IRWebAPIKitDefines.m */, FF7408291296A8E000571D46 /* IRWebAPIKit.h */, @@ -425,6 +428,7 @@ FF9838A815984A4A00CFF2DF /* IRWebAPIRequestOperation.h in Headers */, FF9838AC1598502B00CFF2DF /* IRWebAPIInterceptor.h in Headers */, FFBEE72E15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.h in Headers */, + 130EFA1115E2205400254163 /* JSONKit.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/IRWebAPIResponseParser.m b/IRWebAPIResponseParser.m index 491f55f..6f4f7dc 100644 --- a/IRWebAPIResponseParser.m +++ b/IRWebAPIResponseParser.m @@ -7,6 +7,7 @@ // #import "IRWebAPIResponseParser.h" +#import "JSONKit.h" NSDictionary * IRWebAPIResponseDictionarize (id incomingObject); @@ -102,7 +103,14 @@ IRWebAPIResponseParser IRWebAPIResponseDefaultJSONParserMake () { parserBlock = [^ (NSData *incomingData) { - id results = [NSJSONSerialization JSONObjectWithData:incomingData options:NSJSONReadingAllowFragments error:nil]; + NSError *error = nil; + // sometimes the response from cloud contains invalid utf-8 characters, + // so we deserialize it with loosely restriction + id results = [incomingData objectFromJSONDataWithParseOptions:JKParseOptionLooseUnicode error:&error]; + + if (error && [incomingData length] != 0) { + NSLog(@"Unable to parse JSON response, error:%@", error); + } return IRWebAPIResponseDictionarize(results); diff --git a/JSONKit.h b/JSONKit.h new file mode 100644 index 0000000..71bd0c3 --- /dev/null +++ b/JSONKit.h @@ -0,0 +1,251 @@ +// +// JSONKit.h +// http://github.com/johnezang/JSONKit +// Dual licensed under either the terms of the BSD License, or alternatively +// under the terms of the Apache License, Version 2.0, as specified below. +// + +/* + Copyright (c) 2011, John Engelhart + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the Zang Industries nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + Copyright 2011 John Engelhart + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +#import +#import +#import +#import +#import +#import +#endif // __OBJC__ + +#ifdef __cplusplus +extern "C" { +#endif + + +// For Mac OS X < 10.5. +#ifndef NSINTEGER_DEFINED +#define NSINTEGER_DEFINED +#if defined(__LP64__) || defined(NS_BUILD_32_LIKE_64) +typedef long NSInteger; +typedef unsigned long NSUInteger; +#define NSIntegerMin LONG_MIN +#define NSIntegerMax LONG_MAX +#define NSUIntegerMax ULONG_MAX +#else // defined(__LP64__) || defined(NS_BUILD_32_LIKE_64) +typedef int NSInteger; +typedef unsigned int NSUInteger; +#define NSIntegerMin INT_MIN +#define NSIntegerMax INT_MAX +#define NSUIntegerMax UINT_MAX +#endif // defined(__LP64__) || defined(NS_BUILD_32_LIKE_64) +#endif // NSINTEGER_DEFINED + + +#ifndef _JSONKIT_H_ +#define _JSONKIT_H_ + +#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__APPLE_CC__) && (__APPLE_CC__ >= 5465) +#define JK_DEPRECATED_ATTRIBUTE __attribute__((deprecated)) +#else +#define JK_DEPRECATED_ATTRIBUTE +#endif + +#define JSONKIT_VERSION_MAJOR 1 +#define JSONKIT_VERSION_MINOR 4 + +typedef NSUInteger JKFlags; + +/* + JKParseOptionComments : Allow C style // and /_* ... *_/ (without a _, obviously) comments in JSON. + JKParseOptionUnicodeNewlines : Allow Unicode recommended (?:\r\n|[\n\v\f\r\x85\p{Zl}\p{Zp}]) newlines. + JKParseOptionLooseUnicode : Normally the decoder will stop with an error at any malformed Unicode. + This option allows JSON with malformed Unicode to be parsed without reporting an error. + Any malformed Unicode is replaced with \uFFFD, or "REPLACEMENT CHARACTER". + */ + +enum { + JKParseOptionNone = 0, + JKParseOptionStrict = 0, + JKParseOptionComments = (1 << 0), + JKParseOptionUnicodeNewlines = (1 << 1), + JKParseOptionLooseUnicode = (1 << 2), + JKParseOptionPermitTextAfterValidJSON = (1 << 3), + JKParseOptionValidFlags = (JKParseOptionComments | JKParseOptionUnicodeNewlines | JKParseOptionLooseUnicode | JKParseOptionPermitTextAfterValidJSON), +}; +typedef JKFlags JKParseOptionFlags; + +enum { + JKSerializeOptionNone = 0, + JKSerializeOptionPretty = (1 << 0), + JKSerializeOptionEscapeUnicode = (1 << 1), + JKSerializeOptionEscapeForwardSlashes = (1 << 4), + JKSerializeOptionValidFlags = (JKSerializeOptionPretty | JKSerializeOptionEscapeUnicode | JKSerializeOptionEscapeForwardSlashes), +}; +typedef JKFlags JKSerializeOptionFlags; + +#ifdef __OBJC__ + +typedef struct JKParseState JKParseState; // Opaque internal, private type. + +// As a general rule of thumb, if you use a method that doesn't accept a JKParseOptionFlags argument, it defaults to JKParseOptionStrict + +@interface JSONDecoder : NSObject { + JKParseState *parseState; +} ++ (id)decoder; ++ (id)decoderWithParseOptions:(JKParseOptionFlags)parseOptionFlags; +- (id)initWithParseOptions:(JKParseOptionFlags)parseOptionFlags; +- (void)clearCache; + +// The parse... methods were deprecated in v1.4 in favor of the v1.4 objectWith... methods. +- (id)parseUTF8String:(const unsigned char *)string length:(size_t)length JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithUTF8String:length: instead. +- (id)parseUTF8String:(const unsigned char *)string length:(size_t)length error:(NSError **)error JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithUTF8String:length:error: instead. +// The NSData MUST be UTF8 encoded JSON. +- (id)parseJSONData:(NSData *)jsonData JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithData: instead. +- (id)parseJSONData:(NSData *)jsonData error:(NSError **)error JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithData:error: instead. + +// Methods that return immutable collection objects. +- (id)objectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length; +- (id)objectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length error:(NSError **)error; +// The NSData MUST be UTF8 encoded JSON. +- (id)objectWithData:(NSData *)jsonData; +- (id)objectWithData:(NSData *)jsonData error:(NSError **)error; + +// Methods that return mutable collection objects. +- (id)mutableObjectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length; +- (id)mutableObjectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length error:(NSError **)error; +// The NSData MUST be UTF8 encoded JSON. +- (id)mutableObjectWithData:(NSData *)jsonData; +- (id)mutableObjectWithData:(NSData *)jsonData error:(NSError **)error; + +@end + +//////////// +#pragma mark Deserializing methods +//////////// + +@interface NSString (JSONKitDeserializing) +- (id)objectFromJSONString; +- (id)objectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags; +- (id)objectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error; +- (id)mutableObjectFromJSONString; +- (id)mutableObjectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags; +- (id)mutableObjectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error; +@end + +@interface NSData (JSONKitDeserializing) +// The NSData MUST be UTF8 encoded JSON. +- (id)objectFromJSONData; +- (id)objectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags; +- (id)objectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error; +- (id)mutableObjectFromJSONData; +- (id)mutableObjectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags; +- (id)mutableObjectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error; +@end + +//////////// +#pragma mark Serializing methods +//////////// + +@interface NSString (JSONKitSerializing) +// Convenience methods for those that need to serialize the receiving NSString (i.e., instead of having to serialize a NSArray with a single NSString, you can "serialize to JSON" just the NSString). +// Normally, a string that is serialized to JSON has quotation marks surrounding it, which you may or may not want when serializing a single string, and can be controlled with includeQuotes: +// includeQuotes:YES `a "test"...` -> `"a \"test\"..."` +// includeQuotes:NO `a "test"...` -> `a \"test\"...` +- (NSData *)JSONData; // Invokes JSONDataWithOptions:JKSerializeOptionNone includeQuotes:YES +- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions includeQuotes:(BOOL)includeQuotes error:(NSError **)error; +- (NSString *)JSONString; // Invokes JSONStringWithOptions:JKSerializeOptionNone includeQuotes:YES +- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions includeQuotes:(BOOL)includeQuotes error:(NSError **)error; +@end + +@interface NSArray (JSONKitSerializing) +- (NSData *)JSONData; +- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error; +- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error; +- (NSString *)JSONString; +- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error; +- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error; +@end + +@interface NSDictionary (JSONKitSerializing) +- (NSData *)JSONData; +- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error; +- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error; +- (NSString *)JSONString; +- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error; +- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error; +@end + +#ifdef __BLOCKS__ + +@interface NSArray (JSONKitSerializingBlockAdditions) +- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error; +- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error; +@end + +@interface NSDictionary (JSONKitSerializingBlockAdditions) +- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error; +- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error; +@end + +#endif + + +#endif // __OBJC__ + +#endif // _JSONKIT_H_ + +#ifdef __cplusplus +} // extern "C" +#endif From a5f717f7ac317312b2e7c0189534772d699addca Mon Sep 17 00:00:00 2001 From: syshen Date: Mon, 3 Sep 2012 15:31:22 +0800 Subject: [PATCH 21/32] Notify delegate when remote resource manager download finishes. This fix is for delegate to decrease the count of network reference --- IRRemoteResourceDownloadOperation.h | 4 ++-- IRRemoteResourceDownloadOperation.m | 11 ++++++++--- IRRemoteResourcesManager.h | 2 ++ IRRemoteResourcesManager.m | 7 +++++++ IRWebAPIEngine+ExternalTransforms.h | 2 +- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/IRRemoteResourceDownloadOperation.h b/IRRemoteResourceDownloadOperation.h index 869ae07..c89ec5f 100644 --- a/IRRemoteResourceDownloadOperation.h +++ b/IRRemoteResourceDownloadOperation.h @@ -22,9 +22,9 @@ - (void) remoteResourceDownloadOperationWillBegin:(IRRemoteResourceDownloadOperation *)anOperation; -// @optional +@optional // - (void) remoteResourceDownloadOperation:(IRRemoteResourceDownloadOperation *)anOperation didChangeProgress:(float_t)currentProgress; -// - (void) remoteResourceDownloadOperationDidEnd:(IRRemoteResourceDownloadOperation *)anOperation successfully:(BOOL)wasCompleted; +- (void) remoteResourceDownloadOperationDidEnd:(IRRemoteResourceDownloadOperation *)anOperation successfully:(BOOL)wasCompleted; @end diff --git a/IRRemoteResourceDownloadOperation.m b/IRRemoteResourceDownloadOperation.m index 5b28ae3..05f0ca0 100644 --- a/IRRemoteResourceDownloadOperation.m +++ b/IRRemoteResourceDownloadOperation.m @@ -239,9 +239,11 @@ - (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data - (void) connectionDidFinishLoading:(NSURLConnection *)connection { NSLog(@"Success: %@", [self underlyingRequest].URL); - - if ([self isCancelled]) - return; + if ([self isCancelled]) { + if ([self.delegate respondsToSelector:@selector(remoteResourceDownloadOperationDidEnd:successfully:)]) + [self.delegate remoteResourceDownloadOperationDidEnd:self successfully:NO]; + return; + } [self onOriginalQueue: ^ { @@ -278,6 +280,9 @@ - (void) connectionDidFinishLoading:(NSURLConnection *)connection { self.executing = NO; self.finished = YES; } + + if ([self.delegate respondsToSelector:@selector(remoteResourceDownloadOperationDidEnd:successfully:)]) + [self.delegate remoteResourceDownloadOperationDidEnd:self successfully:YES]; }]; diff --git a/IRRemoteResourcesManager.h b/IRRemoteResourcesManager.h index 2e5e0fd..9092189 100644 --- a/IRRemoteResourcesManager.h +++ b/IRRemoteResourcesManager.h @@ -49,6 +49,8 @@ enum { @property (nonatomic, readwrite, copy) void (^onRemoteResourceDownloadOperationWillBegin)(IRRemoteResourceDownloadOperation *anOperation); +@property (nonatomic, readwrite, copy) void (^ onRemoteResourceDownloadOperationDidEnd) (IRRemoteResourceDownloadOperation *anOperation); + - (void) retrieveResourceAtURL:(NSURL *)inRemoteURL withCompletionBlock:(void(^)(NSURL *tempFileURLOrNil))aBlock; - (void) retrieveResourceAtURL:(NSURL *)inRemoteURL usingPriority:(NSOperationQueuePriority)priority forced:(BOOL)forcesReload withCompletionBlock:(void(^)(NSURL *tempFileURLOrNil))aBlock; diff --git a/IRRemoteResourcesManager.m b/IRRemoteResourcesManager.m index 41c1003..0dd7a6a 100644 --- a/IRRemoteResourcesManager.m +++ b/IRRemoteResourcesManager.m @@ -368,6 +368,13 @@ - (void) remoteResourceDownloadOperationWillBegin:(IRRemoteResourceDownloadOpera } +- (void) remoteResourceDownloadOperationDidEnd:(IRRemoteResourceDownloadOperation *)anOperation successfully:(BOOL)wasCompleted +{ + if (self.onRemoteResourceDownloadOperationDidEnd) + self.onRemoteResourceDownloadOperationDidEnd(anOperation); + +} + - (void) retrieveResourceAtURL:(NSURL *)inRemoteURL withCompletionBlock:(void(^)(NSURL *tempFileURLOrNil))aBlock { [self retrieveResourceAtURL:inRemoteURL usingPriority:NSOperationQueuePriorityNormal forced:NO withCompletionBlock:aBlock]; diff --git a/IRWebAPIEngine+ExternalTransforms.h b/IRWebAPIEngine+ExternalTransforms.h index 3ac50ff..a75ae99 100644 --- a/IRWebAPIEngine+ExternalTransforms.h +++ b/IRWebAPIEngine+ExternalTransforms.h @@ -12,7 +12,7 @@ @interface IRWebAPIEngine (ExternalTransforms) - (NSURLRequest *) transformedRequestWithRequest:(NSURLRequest *)aRequest usingMethodName:(NSString *)aName; - +- (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse withRequestContext:(IRWebAPIRequestContext *)inRequestContext forMethodNamed:(NSString *)inMethodName; // Infers a context object from the request, punts it thru the global pre transformers, method-specific ones if any, then the global post transformers, and finally configures a new request with the transformed context object. @end From 0646118e189366afb920297421ffa5201ce1b6da Mon Sep 17 00:00:00 2001 From: syshen Date: Tue, 4 Sep 2012 09:56:05 +0800 Subject: [PATCH 22/32] remove redundant NSLog --- IRRemoteResourceDownloadOperation.m | 1 - 1 file changed, 1 deletion(-) diff --git a/IRRemoteResourceDownloadOperation.m b/IRRemoteResourceDownloadOperation.m index 5bb7999..35e5fc2 100644 --- a/IRRemoteResourceDownloadOperation.m +++ b/IRRemoteResourceDownloadOperation.m @@ -225,7 +225,6 @@ - (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data - (void) connectionDidFinishLoading:(NSURLConnection *)connection { - NSLog(@"Success: %@", [self underlyingRequest].URL); if ([self isCancelled]) { if ([self.delegate respondsToSelector:@selector(remoteResourceDownloadOperationDidEnd:successfully:)]) [self.delegate remoteResourceDownloadOperationDidEnd:self successfully:NO]; From 7ef0f1fdf9586edb37019b92a6cbfbb2fa6abca3 Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Wed, 19 Sep 2012 12:05:22 +0800 Subject: [PATCH 23/32] Download queue now support cancellation for faster UI responsiveness --- IRRemoteResourceDownloadOperation.m | 1 + IRRemoteResourcesManager.m | 88 ++++++++++++++--------------- 2 files changed, 45 insertions(+), 44 deletions(-) diff --git a/IRRemoteResourceDownloadOperation.m b/IRRemoteResourceDownloadOperation.m index 35e5fc2..add86cb 100644 --- a/IRRemoteResourceDownloadOperation.m +++ b/IRRemoteResourceDownloadOperation.m @@ -252,6 +252,7 @@ - (void) connectionDidFinishLoading:(NSURLConnection *)connection { NSString *fromPath = self.path; NSString *toPath = [[self.path stringByDeletingPathExtension] stringByAppendingPathExtension:pathExtension]; + NSError *error = nil; BOOL didMove = [fm moveItemAtPath:fromPath toPath:toPath error:&error]; diff --git a/IRRemoteResourcesManager.m b/IRRemoteResourcesManager.m index 7e2a25f..065f6d3 100644 --- a/IRRemoteResourcesManager.m +++ b/IRRemoteResourcesManager.m @@ -339,8 +339,8 @@ - (IRRemoteResourceDownloadOperation *) prospectiveOperationForURL:(NSURL *)anUR operation.delegate = self; -// if (enqueuesOperation) -// [self.enqueuedOperations insertObject:operation atIndex:0]; + if (enqueuesOperation) + [self.enqueuedOperations insertObject:operation atIndex:0]; return operation; @@ -416,7 +416,9 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri } if (priority > operation.queuePriority) { + operation.queuePriority = priority; + } } @@ -427,6 +429,8 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri [operation appendCompletionBlock: ^ { + NSAssert(![operation isCancelled], @"canceled operation shouldn't call completion blocks"); + NSString *capturedPath = operation.path; if (![[NSFileManager defaultManager] fileExistsAtPath:capturedPath]) { @@ -458,46 +462,39 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri } - dispatch_sync(dispatch_get_main_queue(), ^{ - [self beginSuspendingOperationQueue]; - }); - - [self.enqueuedOperations insertObject:operation atIndex:0]; - [self enqueueOperationsIfNeeded]; - - dispatch_sync(dispatch_get_main_queue(), ^{ - [self endSuspendingOperationQueue]; + } + + if (isNewOperation || operation.queuePriority > NSOperationQueuePriorityNormal) { + + dispatch_async(dispatch_get_main_queue(), ^{ + + [wSelf beginSuspendingOperationQueue]; + + [wSelf performInBackground: ^ { + + if (!isNewOperation && [wSelf.enqueuedOperations containsObject:operation]) { + + // Hoist it — This is last come, first serve + + [wSelf.enqueuedOperations removeObject:operation]; + [wSelf.enqueuedOperations insertObject:operation atIndex:0]; + + } + + [wSelf enqueueOperationsIfNeeded]; + + dispatch_async(dispatch_get_main_queue(), ^{ + + [wSelf endSuspendingOperationQueue]; + + }); + + }]; + }); } -// dispatch_async(dispatch_get_main_queue(), ^{ -// -// [self beginSuspendingOperationQueue]; -// -// [wSelf performInBackground: ^ { -// -// if ([self.enqueuedOperations containsObject:operation]) { -// -// // Hoist it — This is last come, first serve -// -// [self.enqueuedOperations removeObject:operation]; -// [self.enqueuedOperations insertObject:operation atIndex:0]; -// -// } -// -// [self enqueueOperationsIfNeeded]; -// -// dispatch_async(dispatch_get_main_queue(), ^{ -// -// [self endSuspendingOperationQueue]; -// -// }); -// -// }]; -// -// }); - }]; } @@ -545,9 +542,9 @@ - (void) enqueueOperationsIfNeeded { return (BOOL)![sortedCurrentOperations containsObject:evaluatedObject]; }); -// NSArray *postponedOperations = filtered(sortedCurrentOperations, ^ (id evaluatedObject, NSDictionary *bindings) { -// return (BOOL)![legitimateOperations containsObject:evaluatedObject]; -// }); + NSArray *postponedOperations = filtered(sortedCurrentOperations, ^ (id evaluatedObject, NSDictionary *bindings) { + return (BOOL)![legitimateOperations containsObject:evaluatedObject]; + }); for (IRRemoteResourceDownloadOperation *anOperation in insertedOperations) { if (![self.queue.operations containsObject:anOperation]) { @@ -561,9 +558,12 @@ - (void) enqueueOperationsIfNeeded { [self.enqueuedOperations removeObjectsInArray:insertedOperations]; -// [postponedOperations enumerateObjectsUsingBlock: ^ (IRRemoteResourceDownloadOperation *anOperation, NSUInteger idx, BOOL *stop) { -// [self.enqueuedOperations addObject:[anOperation continuationOperationCancellingCurrentOperation:YES]]; -// }]; + [postponedOperations enumerateObjectsUsingBlock: ^ (IRRemoteResourceDownloadOperation *anOperation, NSUInteger idx, BOOL *stop) { + // create a new download operation, because we don't support resume downloading + IRRemoteResourceDownloadOperation *newOperation = [self prospectiveOperationForURL:anOperation.url enqueue:YES]; + [self removeOperation:anOperation]; + [self addOperation:newOperation]; + }]; } From e87102a1fb4acb272023b9bb4f4b578e83e033f3 Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Tue, 2 Oct 2012 00:10:24 +0800 Subject: [PATCH 24/32] 1. Add key "file_data" for storing binary data in multipart form 2. Key "file" now is a file name string instead of file URL --- IRWebAPIEngine+FormMultipart.m | 48 ++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/IRWebAPIEngine+FormMultipart.m b/IRWebAPIEngine+FormMultipart.m index fe3d56c..32ee6bd 100644 --- a/IRWebAPIEngine+FormMultipart.m +++ b/IRWebAPIEngine+FormMultipart.m @@ -110,29 +110,17 @@ + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { for (id incomingFormName in formNamesToContents) { - // -- ↵ + if ([incomingFormName isEqualToString:@"file_data"]) { + continue; + } + + // -- ↵ [fileHandle writeData:separatorData]; [fileHandle writeData:boundaryData]; [fileHandle writeData:newLineData]; id incomingObject = [formNamesToContents objectForKey:incomingFormName]; - if ([incomingObject isKindOfClass:[NSString class]]) { - - // Append contents of string - - [fileHandle writeData:[[NSString stringWithFormat: - - @"Content-Disposition: form-data; name=\"%@\"", - incomingFormName - - ] dataUsingEncoding:NSUTF8StringEncoding]]; - - [fileHandle writeData:newLineData]; - [fileHandle writeData:newLineData]; - - [fileHandle writeData:[(NSString *)incomingObject dataUsingEncoding:NSUTF8StringEncoding]]; - - } else if ([incomingObject isKindOfClass:[NSURL class]]) { + if ([incomingFormName isEqualToString:@"file"]) { // Append contents of file @@ -140,14 +128,14 @@ + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { @"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"", incomingFormName, - [[(NSURL *)incomingObject path] lastPathComponent] + incomingObject ] dataUsingEncoding:NSUTF8StringEncoding]]; [fileHandle writeData:newLineData]; - NSString *mimeType = IRWebAPIKitMIMETypeOfExtension([[[(NSURL *)incomingObject path] lastPathComponent] pathExtension]); + NSString *mimeType = IRWebAPIKitMIMETypeOfExtension([incomingObject pathExtension]); [fileHandle writeData:[[NSString stringWithFormat: @@ -158,11 +146,27 @@ + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { [fileHandle writeData:newLineData]; [fileHandle writeData:newLineData]; - [fileHandle writeData:[NSData dataWithContentsOfFile:[(NSURL *)incomingObject path] options:NSDataReadingMappedIfSafe error:nil]]; + [fileHandle writeData:[formNamesToContents objectForKey:@"file_data"]]; + } else if ([incomingObject isKindOfClass:[NSString class]]) { + + // Append contents of string + + [fileHandle writeData:[[NSString stringWithFormat: + + @"Content-Disposition: form-data; name=\"%@\"", + incomingFormName + + ] dataUsingEncoding:NSUTF8StringEncoding]]; + + [fileHandle writeData:newLineData]; + [fileHandle writeData:newLineData]; + + [fileHandle writeData:[(NSString *)incomingObject dataUsingEncoding:NSUTF8StringEncoding]]; + } else if ([incomingObject isKindOfClass:[NSData class]]) { - [fileHandle writeData:(NSData *)incomingObject]; + [fileHandle writeData:(NSData *)incomingObject]; } else { From b37002fa5b1b438cddbf02cd7e19ce2dfd339b42 Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Fri, 12 Oct 2012 17:50:26 +0800 Subject: [PATCH 25/32] Elevate open graph image download priority --- IRRemoteResourcesManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IRRemoteResourcesManager.m b/IRRemoteResourcesManager.m index 065f6d3..30c40e8 100644 --- a/IRRemoteResourcesManager.m +++ b/IRRemoteResourcesManager.m @@ -367,7 +367,7 @@ - (void) remoteResourceDownloadOperationDidEnd:(IRRemoteResourceDownloadOperatio - (void) retrieveResourceAtURL:(NSURL *)inRemoteURL withCompletionBlock:(void(^)(NSURL *tempFileURLOrNil))aBlock { - [self retrieveResourceAtURL:inRemoteURL usingPriority:NSOperationQueuePriorityNormal forced:NO withCompletionBlock:aBlock]; + [self retrieveResourceAtURL:inRemoteURL usingPriority:NSOperationQueuePriorityHigh forced:NO withCompletionBlock:aBlock]; } From 8f10c823ddd396280cfa29fe60b195716c9a1f6b Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Tue, 20 Nov 2012 04:00:41 +0800 Subject: [PATCH 26/32] Avoid redundant error logging when failed to download remote resource --- IRRemoteResourceDownloadOperation.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/IRRemoteResourceDownloadOperation.m b/IRRemoteResourceDownloadOperation.m index add86cb..0ef2001 100644 --- a/IRRemoteResourceDownloadOperation.m +++ b/IRRemoteResourceDownloadOperation.m @@ -230,13 +230,14 @@ - (void) connectionDidFinishLoading:(NSURLConnection *)connection { [self.delegate remoteResourceDownloadOperationDidEnd:self successfully:NO]; return; } - + [self onOriginalQueue: ^ { [self.fileHandle closeFile]; self.fileHandle = nil; - if (self.mimeType) { + // no need to move downloaded file for JSON response + if (self.mimeType && ![self.mimeType isEqualToString:@"application/json"]) { // If there is a MIME type available, rename the underlying file From 326ae238eeb7a1843996113112639eedd16e2c5e Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Tue, 20 Nov 2012 14:15:11 +0800 Subject: [PATCH 27/32] Add error handling for corrupted files or invalid mimetype --- IRRemoteResourcesManager.m | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/IRRemoteResourcesManager.m b/IRRemoteResourcesManager.m index 30c40e8..47637e2 100644 --- a/IRRemoteResourcesManager.m +++ b/IRRemoteResourcesManager.m @@ -435,12 +435,17 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri if (![[NSFileManager defaultManager] fileExistsAtPath:capturedPath]) { - [wSelf performInBackground:^{ - - [wSelf removeOperation:operation]; - aBlock(nil); - - }]; + if ([operation.mimeType isEqualToString:@"application/json"]) { + [wSelf performInBackground:^{ + [wSelf removeOperation:operation]; + aBlock(nil); + }]; + } else { + [wSelf performInBackground:^{ + [wSelf removeOperation:operation]; + aBlock([NSURL URLWithString:@"invalidFileURL"]); + }]; + } return; From 41587ad05bd693f8cc910c031f76da7c10d973b9 Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Tue, 20 Nov 2012 16:45:15 +0800 Subject: [PATCH 28/32] Move most file IO work of ResourceDownloadOperation to background --- IRRemoteResourceDownloadOperation.m | 32 +++++++++++++++++++---------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/IRRemoteResourceDownloadOperation.m b/IRRemoteResourceDownloadOperation.m index 0ef2001..a50d9bd 100644 --- a/IRRemoteResourceDownloadOperation.m +++ b/IRRemoteResourceDownloadOperation.m @@ -64,17 +64,27 @@ + (IRRemoteResourceDownloadOperation *) operationWithURL:(NSURL *)aRemoteURL pat } +- (id)init { + + self = [super init]; + + if (self) { + self.actualDispatchQueue = dispatch_queue_create("com.waveface.download.queue", DISPATCH_QUEUE_SERIAL); + } + + return self; + +} + - (void) dealloc { [_connection cancel]; - + dispatch_release(self.actualDispatchQueue); + } - (void) onMainQueue:(void(^)(void))aBlock { - if (!self.actualDispatchQueue) - self.actualDispatchQueue = dispatch_get_current_queue(); - if ([NSThread isMainThread]) { aBlock(); return; @@ -99,13 +109,13 @@ - (void) start { return; } - if ([self isCancelled]) { - self.finished = YES; - return; - } - - self.executing = YES; - [self main]; + if ([self isCancelled]) { + self.finished = YES; + return; + } + + self.executing = YES; + [self main]; } From f3111a7da889e48c4285f49bea51abd25e05a5f5 Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Wed, 26 Dec 2012 20:03:05 +0800 Subject: [PATCH 29/32] Use NSCAssert & NSCParameterAssert in blocks --- IRRemoteResourcesManager.m | 4 ++-- IRWebAPIEngine+FormMultipart.m | 2 +- IRWebAPIXOAuthAuthenticator.m | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/IRRemoteResourcesManager.m b/IRRemoteResourcesManager.m index 47637e2..ed6fef3 100644 --- a/IRRemoteResourcesManager.m +++ b/IRRemoteResourcesManager.m @@ -429,7 +429,7 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri [operation appendCompletionBlock: ^ { - NSAssert(![operation isCancelled], @"canceled operation shouldn't call completion blocks"); + NSCAssert(![operation isCancelled], @"canceled operation shouldn't call completion blocks"); NSString *capturedPath = operation.path; @@ -643,7 +643,7 @@ - (void) retrieveImageAtURL:(NSURL *)inRemoteURL forced:(BOOL)forcesReload withC #else - NSParameterAssert(NO); + NSCParameterAssert(NO); #endif diff --git a/IRWebAPIEngine+FormMultipart.m b/IRWebAPIEngine+FormMultipart.m index 32ee6bd..990a672 100644 --- a/IRWebAPIEngine+FormMultipart.m +++ b/IRWebAPIEngine+FormMultipart.m @@ -170,7 +170,7 @@ + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { } else { - NSAssert(NO, @"%s Can’t understand incoming object %@", __PRETTY_FUNCTION__, incomingObject); + NSCAssert(NO, @"%s Can’t understand incoming object %@", __PRETTY_FUNCTION__, incomingObject); } diff --git a/IRWebAPIXOAuthAuthenticator.m b/IRWebAPIXOAuthAuthenticator.m index ac5fe1c..6d546b8 100644 --- a/IRWebAPIXOAuthAuthenticator.m +++ b/IRWebAPIXOAuthAuthenticator.m @@ -122,7 +122,7 @@ - (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess: [self.currentCredentials.userInfo setObject:self.retrievedToken forKey:@"oauth_token"]; [self.currentCredentials.userInfo setObject:self.retrievedTokenSecret forKey:@"oauth_token_secret"]; - NSParameterAssert(self.currentCredentials && self.currentCredentials.authenticated); + NSCParameterAssert(self.currentCredentials && self.currentCredentials.authenticated); if (successHandler) successHandler(self, YES); From 05b82a1bed8f3a764f40f48ce0049ba03fedd64a Mon Sep 17 00:00:00 2001 From: syshen Date: Tue, 22 Jan 2013 15:46:54 +0800 Subject: [PATCH 30/32] race condition in multi-threads --- IRWebAPIEngine.m | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/IRWebAPIEngine.m b/IRWebAPIEngine.m index 058d3a0..bb5ffce 100644 --- a/IRWebAPIEngine.m +++ b/IRWebAPIEngine.m @@ -144,7 +144,10 @@ - (IRWebAPIRequestOperation *) operationForMethod:(NSString *)method arguments:( - (NSMutableArray *) requestTransformersForMethodNamed:(NSString *)inMethodName { - NSMutableArray *returnedArray = [self.requestTransformers objectForKey:inMethodName]; + NSMutableArray *returnedArray = nil; + + @synchronized(self.requestTransformers) { + returnedArray = [self.requestTransformers objectForKey:inMethodName]; if (!returnedArray) { @@ -152,14 +155,18 @@ - (NSMutableArray *) requestTransformersForMethodNamed:(NSString *)inMethodName [self.requestTransformers setObject:returnedArray forKey:inMethodName]; } + } - return returnedArray; + return returnedArray; } - (NSMutableArray *) responseTransformersForMethodNamed:(NSString *)inMethodName { - NSMutableArray *returnedArray = [self.responseTransformers objectForKey:inMethodName]; + NSMutableArray *returnedArray = nil; + + @synchronized(self.responseTransformers) { + returnedArray = [self.responseTransformers objectForKey:inMethodName]; if (!returnedArray) { @@ -167,8 +174,9 @@ - (NSMutableArray *) responseTransformersForMethodNamed:(NSString *)inMethodName [self.responseTransformers setObject:returnedArray forKey:inMethodName]; } + } - return returnedArray; + return returnedArray; } From 80cca9baea2535a2ecae90a9b118c45f3db79dd0 Mon Sep 17 00:00:00 2001 From: Kevin Chiu Date: Thu, 7 Feb 2013 15:45:05 +0800 Subject: [PATCH 31/32] Fix self-retain cycle --- IRWebAPIXOAuthAuthenticator.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IRWebAPIXOAuthAuthenticator.m b/IRWebAPIXOAuthAuthenticator.m index 6d546b8..314dc31 100644 --- a/IRWebAPIXOAuthAuthenticator.m +++ b/IRWebAPIXOAuthAuthenticator.m @@ -42,7 +42,7 @@ - (void) createTransformerBlocks { self.globalRequestPostTransformerBlock = ^ (IRWebAPIRequestContext *context) { - BOOL isRequestAuthenticated = (BOOL)(!!(self.retrievedTokenSecret)), + BOOL isRequestAuthenticated = (BOOL)(!!(wSelf.retrievedTokenSecret)), isPOST = [@"POST" isEqual:context.method], removesQueryParameters = NO; From 0e36cae675f43b4e4491f0f6af83c56c14a7cea1 Mon Sep 17 00:00:00 2001 From: syshen Date: Thu, 21 Feb 2013 15:48:37 +0800 Subject: [PATCH 32/32] removed temp file created from file upload to reduce the storage usage in app --- IRWebAPIEngine+FormMultipart.m | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/IRWebAPIEngine+FormMultipart.m b/IRWebAPIEngine+FormMultipart.m index 990a672..51b1e51 100644 --- a/IRWebAPIEngine+FormMultipart.m +++ b/IRWebAPIEngine+FormMultipart.m @@ -191,6 +191,13 @@ + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { [context removeAllFormMultipartFieldValues]; [context setMethod:@"POST"]; + if ([[NSFileManager defaultManager] fileExistsAtPath:[fileHandleURL path]]) { + NSError *error = nil; + [[NSFileManager defaultManager] removeItemAtURL:fileHandleURL error:&error]; + if (error != nil) { + NSLog(@"failed to remove cached file for multipart transformer: %@", fileHandleURL); + } + } return context; }) copy];