Initial import
This commit is contained in:
commit
dffe257063
43 changed files with 15505 additions and 0 deletions
36
AFCallback.h
Normal file
36
AFCallback.h
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
// AFCallback.h
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@protocol AFCallback <NSObject>
|
||||||
|
+ (id)callbackWithSuccess:(id)success;
|
||||||
|
+ (id)callbackWithSuccess:(id)success error:(id)error;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface AFCallback : NSObject <AFCallback> {
|
||||||
|
@private
|
||||||
|
id _successBlock;
|
||||||
|
id _errorBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
60
AFCallback.m
Normal file
60
AFCallback.m
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
// AFCallback.m
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import "AFCallback.h"
|
||||||
|
|
||||||
|
@interface AFCallback ()
|
||||||
|
@property (readwrite, nonatomic, copy) id successBlock;
|
||||||
|
@property (readwrite, nonatomic, copy) id errorBlock;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation AFCallback
|
||||||
|
@synthesize successBlock = _successBlock;
|
||||||
|
@synthesize errorBlock = _errorBlock;
|
||||||
|
|
||||||
|
+ (id)callbackWithSuccess:(id)success {
|
||||||
|
return [self callbackWithSuccess:success error:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)callbackWithSuccess:(id)success error:(id)error {
|
||||||
|
id callback = [[[self alloc] init] autorelease];
|
||||||
|
[callback setSuccessBlock:success];
|
||||||
|
[callback setErrorBlock:error];
|
||||||
|
|
||||||
|
return callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init {
|
||||||
|
if ([self class] == [AFCallback class]) {
|
||||||
|
[NSException raise:NSInternalInconsistencyException format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [super init];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[_successBlock release];
|
||||||
|
[_errorBlock release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
52
AFGowallaAPI.h
Normal file
52
AFGowallaAPI.h
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
// AFGowallaAPI.h
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "AFHTTPOperation.h"
|
||||||
|
|
||||||
|
extern NSString * const kAFGowallaClientID;
|
||||||
|
extern NSString * const kAFGowallaClientSecret;
|
||||||
|
|
||||||
|
@interface AFGowallaAPI : NSObject
|
||||||
|
|
||||||
|
+ (NSString *)defaultValueForHeader:(NSString *)header;
|
||||||
|
+ (void)setDefaultHeader:(NSString *)header value:(NSString *)value;
|
||||||
|
+ (void)setAuthorizationHeaderWithToken:(NSString *)token;
|
||||||
|
+ (void)clearAuthorizationHeader;
|
||||||
|
|
||||||
|
+ (NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters;
|
||||||
|
+ (void)enqueueHTTPOperationWithRequest:(NSURLRequest *)request callback:(AFHTTPOperationCallback *)callback;
|
||||||
|
+ (void)enqueueHTTPOperation:(AFHTTPOperation *)operation;
|
||||||
|
|
||||||
|
+ (void)getPath:(NSString *)path parameters:(NSDictionary *)parameters callback:(AFHTTPOperationCallback *)callback;
|
||||||
|
+ (void)postPath:(NSString *)path parameters:(NSDictionary *)parameters callback:(AFHTTPOperationCallback *)callback;
|
||||||
|
+ (void)putPath:(NSString *)path parameters:(NSDictionary *)parameters callback:(AFHTTPOperationCallback *)callback;
|
||||||
|
+ (void)deletePath:(NSString *)path parameters:(NSDictionary *)parameters callback:(AFHTTPOperationCallback *)callback;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark - NSString + AFGowallaAPI
|
||||||
|
|
||||||
|
@interface NSString (AFGowallaAPI)
|
||||||
|
- (NSString *)urlEncodedString;
|
||||||
|
- (NSString *)urlEncodedStringWithEncoding:(NSStringEncoding)encoding;
|
||||||
|
@end
|
||||||
171
AFGowallaAPI.m
Normal file
171
AFGowallaAPI.m
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
// AFGowallaAPI.m
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import "AFGowallaAPI.h"
|
||||||
|
#import "AFHTTPOperation.h"
|
||||||
|
|
||||||
|
// Replace this with your own API Key, available at http://api.gowalla.com/api/keys/
|
||||||
|
NSString * const kAFGowallaClientID = @"e7ccb7d3d2414eb2af4663fc91eb2793";
|
||||||
|
|
||||||
|
static NSString * const kAFGowallaBaseURLString = @"https://api.gowalla.com/";
|
||||||
|
|
||||||
|
static NSStringEncoding const kAFStringEncoding = NSUTF8StringEncoding;
|
||||||
|
|
||||||
|
static NSMutableDictionary *_defaultHeaders = nil;
|
||||||
|
static NSOperationQueue *_operationQueue = nil;
|
||||||
|
|
||||||
|
@implementation AFGowallaAPI
|
||||||
|
|
||||||
|
+ (void)initialize {
|
||||||
|
_operationQueue = [[NSOperationQueue alloc] init];
|
||||||
|
[_operationQueue setMaxConcurrentOperationCount:2];
|
||||||
|
|
||||||
|
_defaultHeaders = [[NSMutableDictionary alloc] init];
|
||||||
|
|
||||||
|
// Accept HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
|
||||||
|
[self setDefaultHeader:@"Accept" value:@"application/json"];
|
||||||
|
|
||||||
|
// Accept-Encoding HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
|
||||||
|
[self setDefaultHeader:@"Accept-Encoding" value:@"gzip"];
|
||||||
|
|
||||||
|
// Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
|
||||||
|
NSString *preferredLanguageCodes = [[NSLocale preferredLanguages] componentsJoinedByString:@", "];
|
||||||
|
[self setDefaultHeader:@"Accept-Language" value:[NSString stringWithFormat:@"%@, en-us;q=0.8", preferredLanguageCodes]];
|
||||||
|
|
||||||
|
// User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
|
||||||
|
[self setDefaultHeader:@"User-Agent" value:[NSString stringWithFormat:@"AFNetworkingExample/%@ (%@, %@ %@, %@, Scale/%f)", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"], @"unknown", [[UIDevice currentDevice] systemName], [[UIDevice currentDevice] systemVersion], [[UIDevice currentDevice] model], ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] ? [[UIScreen mainScreen] scale] : 1.0)]];
|
||||||
|
|
||||||
|
// X-Gowalla-API-Key HTTP Header; see http://api.gowalla.com/api/docs
|
||||||
|
[self setDefaultHeader:@"X-Gowalla-API-Key" value:kAFGowallaClientID];
|
||||||
|
|
||||||
|
// X-Gowalla-API-Version HTTP Header; see http://api.gowalla.com/api/docs
|
||||||
|
[self setDefaultHeader:@"X-Gowalla-API-Version" value:@"1"];
|
||||||
|
|
||||||
|
// X-UDID HTTP Header
|
||||||
|
[self setDefaultHeader:@"X-UDID" value:[[UIDevice currentDevice] uniqueIdentifier]];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)defaultValueForHeader:(NSString *)header {
|
||||||
|
return [_defaultHeaders valueForKey:header];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)setDefaultHeader:(NSString *)header value:(NSString *)value {
|
||||||
|
[_defaultHeaders setObject:value forKey:header];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)setAuthorizationHeaderWithToken:(NSString *)token {
|
||||||
|
[self setDefaultHeader:@"Authorization" value:[NSString stringWithFormat:@"Token token=\"%@\"", token]];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)clearAuthorizationHeader {
|
||||||
|
[_defaultHeaders removeObjectForKey:@"Authorization"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters {
|
||||||
|
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
|
||||||
|
NSMutableDictionary *headers = [_defaultHeaders mutableCopy];
|
||||||
|
NSURL *url = nil;
|
||||||
|
|
||||||
|
NSMutableArray *mutableParameterComponents = [NSMutableArray array];
|
||||||
|
for (id key in [parameters allKeys]) {
|
||||||
|
NSString *component = [NSString stringWithFormat:@"%@=%@", [key urlEncodedStringWithEncoding:kAFStringEncoding], [[parameters valueForKey:key] urlEncodedStringWithEncoding:kAFStringEncoding]];
|
||||||
|
[mutableParameterComponents addObject:component];
|
||||||
|
}
|
||||||
|
NSString *queryString = [mutableParameterComponents componentsJoinedByString:@"&"];
|
||||||
|
|
||||||
|
if ([method isEqualToString:@"GET"]) {
|
||||||
|
path = [path stringByAppendingFormat:[path rangeOfString:@"?"].location == NSNotFound ? @"?%@" : @"&%@", queryString];
|
||||||
|
url = [NSURL URLWithString:path relativeToURL:[NSURL URLWithString:kAFGowallaBaseURLString]];
|
||||||
|
} else {
|
||||||
|
url = [NSURL URLWithString:path relativeToURL:[NSURL URLWithString:kAFGowallaBaseURLString]];
|
||||||
|
NSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(kAFStringEncoding));
|
||||||
|
[headers setObject:[NSString stringWithFormat:@"application/x-www-form-urlencoded; charset=%@", charset] forKey:@"Content-Type"];
|
||||||
|
[request setHTTPBody:[queryString dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
}
|
||||||
|
|
||||||
|
[request setURL:url];
|
||||||
|
[request setHTTPMethod:method];
|
||||||
|
[request setHTTPShouldHandleCookies:NO];
|
||||||
|
[request setAllHTTPHeaderFields:headers];
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)enqueueHTTPOperationWithRequest:(NSURLRequest *)request callback:(AFHTTPOperationCallback *)callback {
|
||||||
|
if ([request URL] == nil || [[request URL] isEqual:[NSNull null]]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AFHTTPOperation *operation = [[[AFHTTPOperation alloc] initWithRequest:request callback:callback] autorelease];
|
||||||
|
[self enqueueHTTPOperation:operation];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)enqueueHTTPOperation:(AFHTTPOperation *)operation {
|
||||||
|
[_operationQueue addOperation:operation];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark HTTP Methods
|
||||||
|
|
||||||
|
+ (void)getPath:(NSString *)path parameters:(NSDictionary *)parameters callback:(AFHTTPOperationCallback *)callback {
|
||||||
|
NSURLRequest *request = [self requestWithMethod:@"GET" path:path parameters:parameters];
|
||||||
|
[self enqueueHTTPOperationWithRequest:request callback:callback];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)postPath:(NSString *)path parameters:(NSDictionary *)parameters callback:(AFHTTPOperationCallback *)callback {
|
||||||
|
NSURLRequest *request = [self requestWithMethod:@"POST" path:path parameters:parameters];
|
||||||
|
[self enqueueHTTPOperationWithRequest:request callback:callback];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)putPath:(NSString *)path parameters:(NSDictionary *)parameters callback:(AFHTTPOperationCallback *)callback {
|
||||||
|
NSURLRequest *request = [self requestWithMethod:@"PUT" path:path parameters:parameters];
|
||||||
|
[self enqueueHTTPOperationWithRequest:request callback:callback];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)deletePath:(NSString *)path parameters:(NSDictionary *)parameters callback:(AFHTTPOperationCallback *)callback {
|
||||||
|
NSURLRequest *request = [self requestWithMethod:@"DELETE" path:path parameters:parameters];
|
||||||
|
[self enqueueHTTPOperationWithRequest:request callback:callback];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation NSString (AFGowallaAPI)
|
||||||
|
|
||||||
|
// See http://github.com/pokeb/asi-http-request/raw/master/Classes/ASIFormDataRequest.m
|
||||||
|
- (NSString*)urlEncodedString {
|
||||||
|
return [self urlEncodedStringWithEncoding:NSUTF8StringEncoding];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)urlEncodedStringWithEncoding:(NSStringEncoding)encoding {
|
||||||
|
NSString *newString = [(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, NULL, CFSTR(":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding(encoding)) autorelease];
|
||||||
|
|
||||||
|
if (newString) {
|
||||||
|
return newString;
|
||||||
|
}
|
||||||
|
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
69
AFHTTPOperation.h
Normal file
69
AFHTTPOperation.h
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
// AFHTTPOperation.h
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "QHTTPOperation.h"
|
||||||
|
#import "AFCallback.h"
|
||||||
|
|
||||||
|
extern NSString * const AFHTTPOperationDidStartNotification;
|
||||||
|
extern NSString * const AFHTTPOperationDidSucceedNotification;
|
||||||
|
extern NSString * const AFHTTPOperationDidFailNotification;
|
||||||
|
|
||||||
|
extern NSString * const AFHTTPOperationParsedDataErrorKey;
|
||||||
|
|
||||||
|
@class AFHTTPOperationCallback;
|
||||||
|
|
||||||
|
// QHTTPOperation/NSOperation subclass that provides JSON parsing and started/finished notifications.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://apple.com"]];
|
||||||
|
// AFHTTPOperation *op = [[[AFHTTPOperation alloc] initWithRequest:request] autorelease];
|
||||||
|
// [[NSOperationQueue mainQueue] addOperation:op];
|
||||||
|
//
|
||||||
|
@interface AFHTTPOperation : QHTTPOperation {
|
||||||
|
@private
|
||||||
|
AFHTTPOperationCallback *_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (nonatomic, retain) AFHTTPOperationCallback *callback;
|
||||||
|
@property (readonly) NSString *responseString;
|
||||||
|
|
||||||
|
+ (id)operationWithRequest:(NSURLRequest *)urlRequest callback:(AFHTTPOperationCallback *)callback;
|
||||||
|
- (id)initWithRequest:(NSURLRequest *)urlRequest callback:(AFHTTPOperationCallback *)callback;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark - AFHTTPOperationCallback
|
||||||
|
|
||||||
|
typedef void (^AFHTTPOperationSuccessBlock)(NSURLRequest *request, NSHTTPURLResponse *response, NSDictionary *data);
|
||||||
|
typedef void (^AFHTTPOperationErrorBlock)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error);
|
||||||
|
|
||||||
|
@protocol AFHTTPOperationCallback <NSObject>
|
||||||
|
@optional
|
||||||
|
+ (id)callbackWithSuccess:(AFHTTPOperationSuccessBlock)success;
|
||||||
|
+ (id)callbackWithSuccess:(AFHTTPOperationSuccessBlock)success error:(AFHTTPOperationErrorBlock)error;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface AFHTTPOperationCallback : AFCallback <AFHTTPOperationCallback>
|
||||||
|
@property (readwrite, nonatomic, copy) AFHTTPOperationSuccessBlock successBlock;
|
||||||
|
@property (readwrite, nonatomic, copy) AFHTTPOperationErrorBlock errorBlock;
|
||||||
|
@end
|
||||||
106
AFHTTPOperation.m
Normal file
106
AFHTTPOperation.m
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
// AFHTTPOperation.m
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import "AFHTTPOperation.h"
|
||||||
|
#import "JSONKit.h"
|
||||||
|
|
||||||
|
NSString * const AFHTTPOperationDidStartNotification = @"com.alamofire.http-operation.start";
|
||||||
|
NSString * const AFHTTPOperationDidSucceedNotification = @"com.alamofire.http-operation.success";
|
||||||
|
NSString * const AFHTTPOperationDidFailNotification = @"com.alamofire.http-operation.failure";
|
||||||
|
|
||||||
|
NSString * const AFHTTPOperationParsedDataErrorKey = @"com.alamofire.http-operation.error.parsed-data";
|
||||||
|
|
||||||
|
@implementation AFHTTPOperation
|
||||||
|
@synthesize callback = _callback;
|
||||||
|
|
||||||
|
+ (id)operationWithRequest:(NSURLRequest *)urlRequest callback:(AFHTTPOperationCallback *)callback {
|
||||||
|
return [[[self alloc] initWithRequest:urlRequest callback:callback] autorelease];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithRequest:(NSURLRequest *)urlRequest callback:(AFHTTPOperationCallback *)callback {
|
||||||
|
self = [super initWithRequest:urlRequest];
|
||||||
|
if (!self) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/plain", nil];
|
||||||
|
self.callback = callback;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[_callback release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)responseString {
|
||||||
|
return [[[NSString alloc] initWithData:self.responseBody encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - QRunLoopOperation
|
||||||
|
|
||||||
|
- (void)operationDidStart {
|
||||||
|
[super operationDidStart];
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:AFHTTPOperationDidStartNotification object:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)finishWithError:(NSError *)error {
|
||||||
|
[super finishWithError:error];
|
||||||
|
|
||||||
|
NSDictionary *data = nil;
|
||||||
|
if (self.contentTypeAcceptable) {
|
||||||
|
if ([[self.lastResponse MIMEType] isEqualToString:@"application/json"]) {
|
||||||
|
NSError *jsonError = nil;
|
||||||
|
data = [[JSONDecoder decoder] parseJSONData:self.responseBody error:&jsonError];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.statusCodeAcceptable) {
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:AFHTTPOperationDidSucceedNotification object:self];
|
||||||
|
|
||||||
|
if(self.callback.successBlock) {
|
||||||
|
self.callback.successBlock(self.lastRequest, self.lastResponse, data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:AFHTTPOperationDidFailNotification object:self];
|
||||||
|
|
||||||
|
NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[error userInfo]];
|
||||||
|
[userInfo setValue:[NSHTTPURLResponse localizedStringForStatusCode:[self.lastResponse statusCode]] forKey:NSLocalizedDescriptionKey];
|
||||||
|
[userInfo setValue:[[self.lastRequest URL] absoluteString] forKey:NSURLErrorFailingURLStringErrorKey];
|
||||||
|
[userInfo setValue:data forKey:AFHTTPOperationParsedDataErrorKey];
|
||||||
|
|
||||||
|
error = [[NSError alloc] initWithDomain:NSURLErrorDomain code:[self.lastResponse statusCode] userInfo:userInfo];
|
||||||
|
|
||||||
|
if (self.callback.errorBlock) {
|
||||||
|
self.callback.errorBlock(self.lastRequest, self.lastResponse, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark - AFHTTPOperationCallback
|
||||||
|
|
||||||
|
@implementation AFHTTPOperationCallback
|
||||||
|
@dynamic successBlock, errorBlock;
|
||||||
|
@end
|
||||||
38
AFImageRequest.h
Normal file
38
AFImageRequest.h
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
// AFImageRequest.h
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import "AFImageRequestOperation.h"
|
||||||
|
|
||||||
|
@protocol AFImageRequester
|
||||||
|
@required
|
||||||
|
- (void)setImageURLString:(NSString *)urlString;
|
||||||
|
- (void)setImageURLString:(NSString *)urlString options:(AFImageRequestOptions)options;
|
||||||
|
@optional
|
||||||
|
@property (nonatomic, copy) NSString *imageURLString;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface AFImageRequest : NSObject
|
||||||
|
|
||||||
|
+ (void)requestImageWithURLString:(NSString *)urlString options:(AFImageRequestOptions)options block:(void (^)(UIImage *image))block;
|
||||||
|
+ (void)requestImageWithURLString:(NSString *)urlString size:(CGSize)imageSize options:(AFImageRequestOptions)options block:(void (^)(UIImage *image))block;
|
||||||
|
|
||||||
|
@end
|
||||||
73
AFImageRequest.m
Normal file
73
AFImageRequest.m
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
// AFImageRequest.m
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import "AFImageRequest.h"
|
||||||
|
#import "AFImageRequestOperation.h"
|
||||||
|
#import "AFURLCache.h"
|
||||||
|
|
||||||
|
static NSOperationQueue *_operationQueue = nil;
|
||||||
|
static NSMutableSet *_cachedRequests = nil;
|
||||||
|
|
||||||
|
@implementation AFImageRequest
|
||||||
|
|
||||||
|
+ (void)initialize {
|
||||||
|
_operationQueue = [[NSOperationQueue alloc] init];
|
||||||
|
[_operationQueue setMaxConcurrentOperationCount:6];
|
||||||
|
|
||||||
|
_cachedRequests = [[NSMutableSet alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)requestImageWithURLString:(NSString *)urlString options:(AFImageRequestOptions)options block:(void (^)(UIImage *image))block {
|
||||||
|
[self requestImageWithURLString:urlString size:CGSizeZero options:options block:block];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)requestImageWithURLString:(NSString *)urlString size:(CGSize)imageSize options:(AFImageRequestOptions)options block:(void (^)(UIImage *image))block {
|
||||||
|
// Append a hash to the image URL so that unique image options get cached separately
|
||||||
|
NSString *cacheKey = [NSString stringWithFormat:@"%fx%f:%d", imageSize.width, imageSize.height, options];
|
||||||
|
NSURL *url = [NSURL URLWithString:[urlString stringByAppendingString:[NSString stringWithFormat:@"#%@", cacheKey]]];
|
||||||
|
if (!url) {
|
||||||
|
if (block) {
|
||||||
|
block(nil);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLCacheStorageAllowed timeoutInterval:30.0];
|
||||||
|
[request setHTTPShouldHandleCookies:NO];
|
||||||
|
|
||||||
|
AFImageRequestOperationCallback *callback = [AFImageRequestOperationCallback callbackWithSuccess:block];
|
||||||
|
callback.options = options;
|
||||||
|
callback.imageSize = imageSize;
|
||||||
|
AFImageRequestOperation *operation = [[[AFImageRequestOperation alloc] initWithRequest:request callback:callback] autorelease];
|
||||||
|
|
||||||
|
NSCachedURLResponse *cachedResponse = [[[[AFURLCache sharedURLCache] cachedResponseForRequest:request] retain] autorelease];
|
||||||
|
if (cachedResponse) {
|
||||||
|
if (block) {
|
||||||
|
block([UIImage imageWithData:[cachedResponse data]]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[_operationQueue addOperation:operation];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
72
AFImageRequestOperation.h
Normal file
72
AFImageRequestOperation.h
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
// AFImageRequestOperation.h
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import "QHTTPOperation.h"
|
||||||
|
#import "AFCallback.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AFImageRequestResize = 1 << 1,
|
||||||
|
AFImageRequestRoundCorners = 1 << 2,
|
||||||
|
AFImageCacheProcessedImage = 1 << 0xA,
|
||||||
|
AFImageRequestDefaultOptions = AFImageRequestResize,
|
||||||
|
} AFImageRequestOptions;
|
||||||
|
|
||||||
|
@class AFImageRequestOperationCallback;
|
||||||
|
|
||||||
|
@interface AFImageRequestOperation : QHTTPOperation {
|
||||||
|
@private
|
||||||
|
AFImageRequestOperationCallback *_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (nonatomic, retain) AFImageRequestOperationCallback *callback;
|
||||||
|
|
||||||
|
- (id)initWithRequest:(NSURLRequest *)someRequest callback:(AFImageRequestOperationCallback *)someCallback;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark - AFHTTPOperationCallback
|
||||||
|
|
||||||
|
typedef void (^AFImageRequestOperationSuccessBlock)(UIImage *image);
|
||||||
|
typedef void (^AFImageRequestOperationErrorBlock)(NSError *error);
|
||||||
|
|
||||||
|
@protocol AFImageRequestOperationCallback <NSObject>
|
||||||
|
@optional
|
||||||
|
+ (id)callbackWithSuccess:(AFImageRequestOperationSuccessBlock)success;
|
||||||
|
+ (id)callbackWithSuccess:(AFImageRequestOperationSuccessBlock)success error:(AFImageRequestOperationErrorBlock)error;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface AFImageRequestOperationCallback : AFCallback <AFImageRequestOperationCallback> {
|
||||||
|
@private
|
||||||
|
CGSize _imageSize;
|
||||||
|
AFImageRequestOptions _options;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (readwrite, nonatomic, assign) CGSize imageSize;
|
||||||
|
@property (readwrite, nonatomic, assign) AFImageRequestOptions options;
|
||||||
|
|
||||||
|
@property (readwrite, nonatomic, copy) AFImageRequestOperationSuccessBlock successBlock;
|
||||||
|
@property (readwrite, nonatomic, copy) AFImageRequestOperationErrorBlock errorBlock;
|
||||||
|
|
||||||
|
+ (id)callbackWithSuccess:(AFImageRequestOperationSuccessBlock)success imageSize:(CGSize)imageSize options:(AFImageRequestOptions)options;
|
||||||
|
@end
|
||||||
140
AFImageRequestOperation.m
Normal file
140
AFImageRequestOperation.m
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
// AFImageRequestOperation.m
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import "AFImageRequestOperation.h"
|
||||||
|
#import "AFURLCache.h"
|
||||||
|
|
||||||
|
#import "UIImage+AFNetworking.h"
|
||||||
|
|
||||||
|
const CGFloat kAFImageRequestJPEGQuality = 0.8;
|
||||||
|
const NSUInteger kAFImageRequestMaximumResponseSize = 8 * 1024 * 1024;
|
||||||
|
static inline CGSize kAFImageRequestRoundedCornerRadii(CGSize imageSize) {
|
||||||
|
CGFloat dimension = fmaxf(imageSize.width, imageSize.height);
|
||||||
|
return CGSizeMake(dimension, dimension);
|
||||||
|
}
|
||||||
|
|
||||||
|
@implementation AFImageRequestOperation
|
||||||
|
@synthesize callback;
|
||||||
|
|
||||||
|
- (id)initWithRequest:(NSURLRequest *)someRequest callback:(AFImageRequestOperationCallback *)someCallback {
|
||||||
|
self = [super initWithRequest:someRequest];
|
||||||
|
if (!self) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.maximumResponseSize = kAFImageRequestMaximumResponseSize;
|
||||||
|
|
||||||
|
NSMutableIndexSet *statusCodes = [NSMutableIndexSet indexSetWithIndex:0];
|
||||||
|
[statusCodes addIndexesInRange:NSMakeRange(200, 100)];
|
||||||
|
self.acceptableStatusCodes = statusCodes;
|
||||||
|
self.acceptableContentTypes = [NSSet setWithObjects:@"image/png", @"image/jpeg", @"image/pjpeg", @"image/gif", @"application/x-0", nil];
|
||||||
|
self.callback = someCallback;
|
||||||
|
|
||||||
|
if (self.callback) {
|
||||||
|
self.runLoopModes = [NSSet setWithObjects:NSRunLoopCommonModes, NSDefaultRunLoopMode, nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - QHTTPRequestOperation
|
||||||
|
|
||||||
|
// QHTTPRequestOperation requires this to return an NSHTTPURLResponse, but in certain circumstances,
|
||||||
|
// this method would otherwise return an instance of its superclass, NSURLResponse
|
||||||
|
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
|
||||||
|
if([response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||||
|
[super connection:connection didReceiveResponse:response];
|
||||||
|
} else {
|
||||||
|
[super connection:connection didReceiveResponse:[[[NSHTTPURLResponse alloc] initWithURL:[response URL] MIMEType:[response MIMEType] expectedContentLength:[response expectedContentLength] textEncodingName:[response textEncodingName]] autorelease]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - QRunLoopOperation
|
||||||
|
|
||||||
|
- (void)finishWithError:(NSError *)error {
|
||||||
|
[super finishWithError:error];
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
if (callback.errorBlock) {
|
||||||
|
callback.errorBlock(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIImage *image = nil;
|
||||||
|
if ([[UIScreen mainScreen] scale] == 2.0) {
|
||||||
|
CGImageRef imageRef = [UIImage imageWithData:self.responseBody].CGImage;
|
||||||
|
image = [UIImage imageWithCGImage:imageRef scale:2.0 orientation:UIImageOrientationUp];
|
||||||
|
} else {
|
||||||
|
image = [UIImage imageWithData:self.responseBody];
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL didProcessingOnImage = NO;
|
||||||
|
|
||||||
|
if ((self.callback.options & AFImageRequestResize) && !(CGSizeEqualToSize(image.size, self.callback.imageSize) || CGSizeEqualToSize(self.callback.imageSize, CGSizeZero))) {
|
||||||
|
image = [UIImage imageByScalingAndCroppingImage:image size:self.callback.imageSize];
|
||||||
|
didProcessingOnImage = YES;
|
||||||
|
}
|
||||||
|
if ((self.callback.options & AFImageRequestRoundCorners)) {
|
||||||
|
image = [UIImage imageByRoundingCornersOfImage:image corners:UIRectCornerAllCorners cornerRadii:kAFImageRequestRoundedCornerRadii(image.size)];
|
||||||
|
didProcessingOnImage = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (self.callback.successBlock) {
|
||||||
|
self.callback.successBlock(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((self.callback.options & AFImageCacheProcessedImage) && didProcessingOnImage) {
|
||||||
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
NSData *processedImageData = nil;
|
||||||
|
if ((self.callback.options & AFImageRequestRoundCorners) || [[[[self.lastRequest URL] path] pathExtension] isEqualToString:@"png"]) {
|
||||||
|
processedImageData = UIImagePNGRepresentation(image);
|
||||||
|
} else {
|
||||||
|
processedImageData = UIImageJPEGRepresentation(image, kAFImageRequestJPEGQuality);
|
||||||
|
}
|
||||||
|
NSURLResponse *response = [[[NSURLResponse alloc] initWithURL:[self.lastRequest URL] MIMEType:[self.lastResponse MIMEType] expectedContentLength:[processedImageData length] textEncodingName:[self.lastResponse textEncodingName]] autorelease];
|
||||||
|
NSCachedURLResponse *cachedResponse = [[[NSCachedURLResponse alloc] initWithResponse:response data:processedImageData] autorelease];
|
||||||
|
[[AFURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:self.lastRequest];
|
||||||
|
[pool drain];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark - AFHTTPOperationCallback
|
||||||
|
|
||||||
|
@implementation AFImageRequestOperationCallback : AFCallback
|
||||||
|
@synthesize options = _options;
|
||||||
|
@synthesize imageSize = _imageSize;
|
||||||
|
@dynamic successBlock, errorBlock;
|
||||||
|
|
||||||
|
+ (id)callbackWithSuccess:(AFImageRequestOperationSuccessBlock)success imageSize:(CGSize)imageSize options:(AFImageRequestOptions)options {
|
||||||
|
id callback = [self callbackWithSuccess:success];
|
||||||
|
[callback setImageSize:imageSize];
|
||||||
|
[callback setOptions:options];
|
||||||
|
|
||||||
|
return callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
440
AFNetworkingExample.xcodeproj/project.pbxproj
Normal file
440
AFNetworkingExample.xcodeproj/project.pbxproj
Normal file
|
|
@ -0,0 +1,440 @@
|
||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 46;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
F8E469651395739D00DB05C8 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8E469641395739D00DB05C8 /* UIKit.framework */; };
|
||||||
|
F8E469671395739D00DB05C8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8E469661395739D00DB05C8 /* Foundation.framework */; };
|
||||||
|
F8E469691395739D00DB05C8 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8E469681395739D00DB05C8 /* CoreGraphics.framework */; };
|
||||||
|
F8E469721395739D00DB05C8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469711395739D00DB05C8 /* main.m */; };
|
||||||
|
F8E469751395739D00DB05C8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469741395739D00DB05C8 /* AppDelegate.m */; };
|
||||||
|
F8E4698E1395742500DB05C8 /* AFCallback.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469851395742500DB05C8 /* AFCallback.m */; };
|
||||||
|
F8E4698F1395742500DB05C8 /* AFHTTPOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469871395742500DB05C8 /* AFHTTPOperation.m */; };
|
||||||
|
F8E469901395742500DB05C8 /* AFImageRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469891395742500DB05C8 /* AFImageRequestOperation.m */; };
|
||||||
|
F8E469911395742500DB05C8 /* AFURLCache.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E4698B1395742500DB05C8 /* AFURLCache.m */; };
|
||||||
|
F8E469921395742500DB05C8 /* UIImage+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E4698D1395742500DB05C8 /* UIImage+AFNetworking.m */; };
|
||||||
|
F8E469A9139574DA00DB05C8 /* QHTTPOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469A4139574DA00DB05C8 /* QHTTPOperation.m */; };
|
||||||
|
F8E469AA139574DA00DB05C8 /* QReachabilityOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469A6139574DA00DB05C8 /* QReachabilityOperation.m */; };
|
||||||
|
F8E469AB139574DA00DB05C8 /* QRunLoopOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469A8139574DA00DB05C8 /* QRunLoopOperation.m */; };
|
||||||
|
F8E469B31395752400DB05C8 /* JSONKit.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469B21395752400DB05C8 /* JSONKit.m */; };
|
||||||
|
F8E469BC139575D000DB05C8 /* AFGowallaAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469B9139575D000DB05C8 /* AFGowallaAPI.m */; };
|
||||||
|
F8E469BD139575D000DB05C8 /* AFImageRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469BB139575D000DB05C8 /* AFImageRequest.m */; };
|
||||||
|
F8E469CB139577E000DB05C8 /* NearbySpotsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469C8139577E000DB05C8 /* NearbySpotsViewController.m */; };
|
||||||
|
F8E469CE1395780600DB05C8 /* SpotTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469CD1395780600DB05C8 /* SpotTableViewCell.m */; };
|
||||||
|
F8E469D11395781500DB05C8 /* Spot.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469D01395781500DB05C8 /* Spot.m */; };
|
||||||
|
F8E469DF13957DD500DB05C8 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8E469DE13957DD500DB05C8 /* CoreLocation.framework */; };
|
||||||
|
F8E469E113957DF100DB05C8 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8E469E013957DF100DB05C8 /* Security.framework */; };
|
||||||
|
F8E469E513957E0400DB05C8 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8E469E413957E0400DB05C8 /* SystemConfiguration.framework */; };
|
||||||
|
F8E469EC13957FC500DB05C8 /* TTTLocationFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E469EB13957FC500DB05C8 /* TTTLocationFormatter.m */; };
|
||||||
|
F8E469F01395812A00DB05C8 /* placeholder-stamp.png in Resources */ = {isa = PBXBuildFile; fileRef = F8E469EE1395812A00DB05C8 /* placeholder-stamp.png */; };
|
||||||
|
F8E469F11395812A00DB05C8 /* placeholder-stamp@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F8E469EF1395812A00DB05C8 /* placeholder-stamp@2x.png */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
F8E469601395739C00DB05C8 /* AFNetworkingExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AFNetworkingExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
F8E469641395739D00DB05C8 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||||
|
F8E469661395739D00DB05C8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||||
|
F8E469681395739D00DB05C8 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
||||||
|
F8E4696C1395739D00DB05C8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
F8E469701395739D00DB05C8 /* Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = "<group>"; };
|
||||||
|
F8E469711395739D00DB05C8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||||
|
F8E469731395739D00DB05C8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||||
|
F8E469741395739D00DB05C8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||||
|
F8E469841395742500DB05C8 /* AFCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFCallback.h; sourceTree = "<group>"; };
|
||||||
|
F8E469851395742500DB05C8 /* AFCallback.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFCallback.m; sourceTree = "<group>"; };
|
||||||
|
F8E469861395742500DB05C8 /* AFHTTPOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFHTTPOperation.h; sourceTree = "<group>"; };
|
||||||
|
F8E469871395742500DB05C8 /* AFHTTPOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFHTTPOperation.m; sourceTree = "<group>"; };
|
||||||
|
F8E469881395742500DB05C8 /* AFImageRequestOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFImageRequestOperation.h; sourceTree = "<group>"; };
|
||||||
|
F8E469891395742500DB05C8 /* AFImageRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFImageRequestOperation.m; sourceTree = "<group>"; };
|
||||||
|
F8E4698A1395742500DB05C8 /* AFURLCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFURLCache.h; sourceTree = "<group>"; };
|
||||||
|
F8E4698B1395742500DB05C8 /* AFURLCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFURLCache.m; sourceTree = "<group>"; };
|
||||||
|
F8E4698C1395742500DB05C8 /* UIImage+AFNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+AFNetworking.h"; sourceTree = "<group>"; };
|
||||||
|
F8E4698D1395742500DB05C8 /* UIImage+AFNetworking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+AFNetworking.m"; sourceTree = "<group>"; };
|
||||||
|
F8E469A3139574DA00DB05C8 /* QHTTPOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QHTTPOperation.h; sourceTree = "<group>"; };
|
||||||
|
F8E469A4139574DA00DB05C8 /* QHTTPOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QHTTPOperation.m; sourceTree = "<group>"; };
|
||||||
|
F8E469A5139574DA00DB05C8 /* QReachabilityOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QReachabilityOperation.h; sourceTree = "<group>"; };
|
||||||
|
F8E469A6139574DA00DB05C8 /* QReachabilityOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QReachabilityOperation.m; sourceTree = "<group>"; };
|
||||||
|
F8E469A7139574DA00DB05C8 /* QRunLoopOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRunLoopOperation.h; sourceTree = "<group>"; };
|
||||||
|
F8E469A8139574DA00DB05C8 /* QRunLoopOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRunLoopOperation.m; sourceTree = "<group>"; };
|
||||||
|
F8E469B11395752400DB05C8 /* JSONKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONKit.h; sourceTree = "<group>"; };
|
||||||
|
F8E469B21395752400DB05C8 /* JSONKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSONKit.m; sourceTree = "<group>"; };
|
||||||
|
F8E469B8139575D000DB05C8 /* AFGowallaAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFGowallaAPI.h; sourceTree = "<group>"; };
|
||||||
|
F8E469B9139575D000DB05C8 /* AFGowallaAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFGowallaAPI.m; sourceTree = "<group>"; };
|
||||||
|
F8E469BA139575D000DB05C8 /* AFImageRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFImageRequest.h; sourceTree = "<group>"; };
|
||||||
|
F8E469BB139575D000DB05C8 /* AFImageRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFImageRequest.m; sourceTree = "<group>"; };
|
||||||
|
F8E469C7139577E000DB05C8 /* NearbySpotsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NearbySpotsViewController.h; sourceTree = "<group>"; };
|
||||||
|
F8E469C8139577E000DB05C8 /* NearbySpotsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NearbySpotsViewController.m; sourceTree = "<group>"; };
|
||||||
|
F8E469CC1395780600DB05C8 /* SpotTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpotTableViewCell.h; sourceTree = "<group>"; };
|
||||||
|
F8E469CD1395780600DB05C8 /* SpotTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SpotTableViewCell.m; sourceTree = "<group>"; };
|
||||||
|
F8E469CF1395781500DB05C8 /* Spot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Spot.h; sourceTree = "<group>"; };
|
||||||
|
F8E469D01395781500DB05C8 /* Spot.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Spot.m; sourceTree = "<group>"; };
|
||||||
|
F8E469DE13957DD500DB05C8 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; };
|
||||||
|
F8E469E013957DF100DB05C8 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
|
||||||
|
F8E469E213957DF700DB05C8 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
|
||||||
|
F8E469E413957E0400DB05C8 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
|
||||||
|
F8E469EA13957FC500DB05C8 /* TTTLocationFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTTLocationFormatter.h; sourceTree = "<group>"; };
|
||||||
|
F8E469EB13957FC500DB05C8 /* TTTLocationFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTTLocationFormatter.m; sourceTree = "<group>"; };
|
||||||
|
F8E469EE1395812A00DB05C8 /* placeholder-stamp.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "placeholder-stamp.png"; sourceTree = "<group>"; };
|
||||||
|
F8E469EF1395812A00DB05C8 /* placeholder-stamp@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "placeholder-stamp@2x.png"; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
F8E4695D1395739C00DB05C8 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
F8E469651395739D00DB05C8 /* UIKit.framework in Frameworks */,
|
||||||
|
F8E469671395739D00DB05C8 /* Foundation.framework in Frameworks */,
|
||||||
|
F8E469691395739D00DB05C8 /* CoreGraphics.framework in Frameworks */,
|
||||||
|
F8E469DF13957DD500DB05C8 /* CoreLocation.framework in Frameworks */,
|
||||||
|
F8E469E513957E0400DB05C8 /* SystemConfiguration.framework in Frameworks */,
|
||||||
|
F8E469E113957DF100DB05C8 /* Security.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
F8E469551395739C00DB05C8 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469B71395759C00DB05C8 /* Networking Extensions */,
|
||||||
|
F8E4696A1395739D00DB05C8 /* Classes */,
|
||||||
|
F8E469ED1395812A00DB05C8 /* Images */,
|
||||||
|
F8E469931395743A00DB05C8 /* Vendor */,
|
||||||
|
F8E469631395739D00DB05C8 /* Frameworks */,
|
||||||
|
F8E469611395739C00DB05C8 /* Products */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F8E469611395739C00DB05C8 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469601395739C00DB05C8 /* AFNetworkingExample.app */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F8E469631395739D00DB05C8 /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469E413957E0400DB05C8 /* SystemConfiguration.framework */,
|
||||||
|
F8E469E213957DF700DB05C8 /* SystemConfiguration.framework */,
|
||||||
|
F8E469E013957DF100DB05C8 /* Security.framework */,
|
||||||
|
F8E469DE13957DD500DB05C8 /* CoreLocation.framework */,
|
||||||
|
F8E469641395739D00DB05C8 /* UIKit.framework */,
|
||||||
|
F8E469661395739D00DB05C8 /* Foundation.framework */,
|
||||||
|
F8E469681395739D00DB05C8 /* CoreGraphics.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F8E4696A1395739D00DB05C8 /* Classes */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469C9139577E000DB05C8 /* Models */,
|
||||||
|
F8E469CA139577E000DB05C8 /* Views */,
|
||||||
|
F8E469C6139577E000DB05C8 /* Controllers */,
|
||||||
|
F8E4696B1395739D00DB05C8 /* Supporting Files */,
|
||||||
|
);
|
||||||
|
name = Classes;
|
||||||
|
path = AFNetworkingExample;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F8E4696B1395739D00DB05C8 /* Supporting Files */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469711395739D00DB05C8 /* main.m */,
|
||||||
|
F8E469701395739D00DB05C8 /* Prefix.pch */,
|
||||||
|
F8E469731395739D00DB05C8 /* AppDelegate.h */,
|
||||||
|
F8E469741395739D00DB05C8 /* AppDelegate.m */,
|
||||||
|
F8E4696C1395739D00DB05C8 /* Info.plist */,
|
||||||
|
);
|
||||||
|
name = "Supporting Files";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F8E469931395743A00DB05C8 /* Vendor */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469941395744600DB05C8 /* Alamofire */,
|
||||||
|
F8E469A2139574DA00DB05C8 /* QHTTPOperation */,
|
||||||
|
F8E469B01395752400DB05C8 /* JSONKit */,
|
||||||
|
F8E469E613957F8900DB05C8 /* TTT */,
|
||||||
|
);
|
||||||
|
name = Vendor;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F8E469941395744600DB05C8 /* Alamofire */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469841395742500DB05C8 /* AFCallback.h */,
|
||||||
|
F8E469851395742500DB05C8 /* AFCallback.m */,
|
||||||
|
F8E469861395742500DB05C8 /* AFHTTPOperation.h */,
|
||||||
|
F8E469871395742500DB05C8 /* AFHTTPOperation.m */,
|
||||||
|
F8E469881395742500DB05C8 /* AFImageRequestOperation.h */,
|
||||||
|
F8E469891395742500DB05C8 /* AFImageRequestOperation.m */,
|
||||||
|
F8E4698A1395742500DB05C8 /* AFURLCache.h */,
|
||||||
|
F8E4698B1395742500DB05C8 /* AFURLCache.m */,
|
||||||
|
F8E4698C1395742500DB05C8 /* UIImage+AFNetworking.h */,
|
||||||
|
F8E4698D1395742500DB05C8 /* UIImage+AFNetworking.m */,
|
||||||
|
);
|
||||||
|
name = Alamofire;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F8E469A2139574DA00DB05C8 /* QHTTPOperation */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469A3139574DA00DB05C8 /* QHTTPOperation.h */,
|
||||||
|
F8E469A4139574DA00DB05C8 /* QHTTPOperation.m */,
|
||||||
|
F8E469A5139574DA00DB05C8 /* QReachabilityOperation.h */,
|
||||||
|
F8E469A6139574DA00DB05C8 /* QReachabilityOperation.m */,
|
||||||
|
F8E469A7139574DA00DB05C8 /* QRunLoopOperation.h */,
|
||||||
|
F8E469A8139574DA00DB05C8 /* QRunLoopOperation.m */,
|
||||||
|
);
|
||||||
|
path = QHTTPOperation;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F8E469B01395752400DB05C8 /* JSONKit */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469B11395752400DB05C8 /* JSONKit.h */,
|
||||||
|
F8E469B21395752400DB05C8 /* JSONKit.m */,
|
||||||
|
);
|
||||||
|
name = JSONKit;
|
||||||
|
path = AFNetworkingExample/Vendor/JSONKit;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F8E469B71395759C00DB05C8 /* Networking Extensions */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469B8139575D000DB05C8 /* AFGowallaAPI.h */,
|
||||||
|
F8E469B9139575D000DB05C8 /* AFGowallaAPI.m */,
|
||||||
|
F8E469BA139575D000DB05C8 /* AFImageRequest.h */,
|
||||||
|
F8E469BB139575D000DB05C8 /* AFImageRequest.m */,
|
||||||
|
);
|
||||||
|
name = "Networking Extensions";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F8E469C6139577E000DB05C8 /* Controllers */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469C7139577E000DB05C8 /* NearbySpotsViewController.h */,
|
||||||
|
F8E469C8139577E000DB05C8 /* NearbySpotsViewController.m */,
|
||||||
|
);
|
||||||
|
name = Controllers;
|
||||||
|
path = Classes/Controllers;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F8E469C9139577E000DB05C8 /* Models */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469CF1395781500DB05C8 /* Spot.h */,
|
||||||
|
F8E469D01395781500DB05C8 /* Spot.m */,
|
||||||
|
);
|
||||||
|
name = Models;
|
||||||
|
path = Classes/Models;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F8E469CA139577E000DB05C8 /* Views */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469CC1395780600DB05C8 /* SpotTableViewCell.h */,
|
||||||
|
F8E469CD1395780600DB05C8 /* SpotTableViewCell.m */,
|
||||||
|
);
|
||||||
|
name = Views;
|
||||||
|
path = Classes/Views;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F8E469E613957F8900DB05C8 /* TTT */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469EA13957FC500DB05C8 /* TTTLocationFormatter.h */,
|
||||||
|
F8E469EB13957FC500DB05C8 /* TTTLocationFormatter.m */,
|
||||||
|
);
|
||||||
|
name = TTT;
|
||||||
|
path = AFNetworkingExample/Vendor/TTT;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F8E469ED1395812A00DB05C8 /* Images */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F8E469EE1395812A00DB05C8 /* placeholder-stamp.png */,
|
||||||
|
F8E469EF1395812A00DB05C8 /* placeholder-stamp@2x.png */,
|
||||||
|
);
|
||||||
|
name = Images;
|
||||||
|
path = AFNetworkingExample/Images;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
F8E4695F1395739C00DB05C8 /* AFNetworkingExample */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = F8E469811395739D00DB05C8 /* Build configuration list for PBXNativeTarget "AFNetworkingExample" */;
|
||||||
|
buildPhases = (
|
||||||
|
F8E4695C1395739C00DB05C8 /* Sources */,
|
||||||
|
F8E4695D1395739C00DB05C8 /* Frameworks */,
|
||||||
|
F8E4695E1395739C00DB05C8 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = AFNetworkingExample;
|
||||||
|
productName = AFNetworkingExample;
|
||||||
|
productReference = F8E469601395739C00DB05C8 /* AFNetworkingExample.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
F8E469571395739C00DB05C8 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
ORGANIZATIONNAME = Gowalla;
|
||||||
|
};
|
||||||
|
buildConfigurationList = F8E4695A1395739C00DB05C8 /* Build configuration list for PBXProject "AFNetworkingExample" */;
|
||||||
|
compatibilityVersion = "Xcode 3.2";
|
||||||
|
developmentRegion = English;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
);
|
||||||
|
mainGroup = F8E469551395739C00DB05C8;
|
||||||
|
productRefGroup = F8E469611395739C00DB05C8 /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
F8E4695F1395739C00DB05C8 /* AFNetworkingExample */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
F8E4695E1395739C00DB05C8 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
F8E469F01395812A00DB05C8 /* placeholder-stamp.png in Resources */,
|
||||||
|
F8E469F11395812A00DB05C8 /* placeholder-stamp@2x.png in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
F8E4695C1395739C00DB05C8 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
F8E469721395739D00DB05C8 /* main.m in Sources */,
|
||||||
|
F8E469751395739D00DB05C8 /* AppDelegate.m in Sources */,
|
||||||
|
F8E4698E1395742500DB05C8 /* AFCallback.m in Sources */,
|
||||||
|
F8E4698F1395742500DB05C8 /* AFHTTPOperation.m in Sources */,
|
||||||
|
F8E469901395742500DB05C8 /* AFImageRequestOperation.m in Sources */,
|
||||||
|
F8E469911395742500DB05C8 /* AFURLCache.m in Sources */,
|
||||||
|
F8E469921395742500DB05C8 /* UIImage+AFNetworking.m in Sources */,
|
||||||
|
F8E469A9139574DA00DB05C8 /* QHTTPOperation.m in Sources */,
|
||||||
|
F8E469AA139574DA00DB05C8 /* QReachabilityOperation.m in Sources */,
|
||||||
|
F8E469AB139574DA00DB05C8 /* QRunLoopOperation.m in Sources */,
|
||||||
|
F8E469B31395752400DB05C8 /* JSONKit.m in Sources */,
|
||||||
|
F8E469BC139575D000DB05C8 /* AFGowallaAPI.m in Sources */,
|
||||||
|
F8E469BD139575D000DB05C8 /* AFImageRequest.m in Sources */,
|
||||||
|
F8E469CB139577E000DB05C8 /* NearbySpotsViewController.m in Sources */,
|
||||||
|
F8E469CE1395780600DB05C8 /* SpotTableViewCell.m in Sources */,
|
||||||
|
F8E469D11395781500DB05C8 /* Spot.m in Sources */,
|
||||||
|
F8E469EC13957FC500DB05C8 /* TTTLocationFormatter.m in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
F8E4697F1395739D00DB05C8 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
|
||||||
|
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||||
|
GCC_VERSION = com.apple.compilers.llvmgcc42;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
F8E469801395739D00DB05C8 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_VERSION = com.apple.compilers.llvmgcc42;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
|
||||||
|
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
F8E469821395739D00DB05C8 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
|
GCC_PREFIX_HEADER = AFNetworkingExample/Prefix.pch;
|
||||||
|
INFOPLIST_FILE = AFNetworkingExample/Info.plist;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
WRAPPER_EXTENSION = app;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
F8E469831395739D00DB05C8 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
COPY_PHASE_STRIP = YES;
|
||||||
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
|
GCC_PREFIX_HEADER = AFNetworkingExample/Prefix.pch;
|
||||||
|
INFOPLIST_FILE = AFNetworkingExample/Info.plist;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
WRAPPER_EXTENSION = app;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
F8E4695A1395739C00DB05C8 /* Build configuration list for PBXProject "AFNetworkingExample" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
F8E4697F1395739D00DB05C8 /* Debug */,
|
||||||
|
F8E469801395739D00DB05C8 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
F8E469811395739D00DB05C8 /* Build configuration list for PBXNativeTarget "AFNetworkingExample" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
F8E469821395739D00DB05C8 /* Debug */,
|
||||||
|
F8E469831395739D00DB05C8 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = F8E469571395739C00DB05C8 /* Project object */;
|
||||||
|
}
|
||||||
7
AFNetworkingExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
AFNetworkingExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:AFNetworkingExample.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEWorkspaceUserSettings_HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges</key>
|
||||||
|
<true/>
|
||||||
|
<key>IDEWorkspaceUserSettings_SnapshotAutomaticallyBeforeSignificantChanges</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
version = "1.3">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "F8E4695F1395739C00DB05C8"
|
||||||
|
BuildableName = "AFNetworkingExample.app"
|
||||||
|
BlueprintName = "AFNetworkingExample"
|
||||||
|
ReferencedContainer = "container:AFNetworkingExample.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
|
||||||
|
displayScaleIsEnabled = "NO"
|
||||||
|
displayScale = "1.00"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
<BuildableProductRunnable>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "F8E4695F1395739C00DB05C8"
|
||||||
|
BuildableName = "AFNetworkingExample.app"
|
||||||
|
BlueprintName = "AFNetworkingExample"
|
||||||
|
ReferencedContainer = "container:AFNetworkingExample.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
displayScaleIsEnabled = "NO"
|
||||||
|
displayScale = "1.00"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
buildConfiguration = "Release">
|
||||||
|
<BuildableProductRunnable>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "F8E4695F1395739C00DB05C8"
|
||||||
|
BuildableName = "AFNetworkingExample.app"
|
||||||
|
BlueprintName = "AFNetworkingExample"
|
||||||
|
ReferencedContainer = "container:AFNetworkingExample.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>SchemeUserState</key>
|
||||||
|
<dict>
|
||||||
|
<key>AFNetworkingExample.xcscheme</key>
|
||||||
|
<dict>
|
||||||
|
<key>orderHint</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>SuppressBuildableAutocreation</key>
|
||||||
|
<dict>
|
||||||
|
<key>F8E4695F1395739C00DB05C8</key>
|
||||||
|
<dict>
|
||||||
|
<key>primary</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
32
AFNetworkingExample/AppDelegate.h
Normal file
32
AFNetworkingExample/AppDelegate.h
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
// AFNetworkingExampleAppDelegate.h
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@interface AppDelegate : NSObject <UIApplicationDelegate> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (nonatomic, retain) UIWindow *window;
|
||||||
|
@property (nonatomic, retain) UINavigationController *navigationController;
|
||||||
|
|
||||||
|
@end
|
||||||
50
AFNetworkingExample/AppDelegate.m
Normal file
50
AFNetworkingExample/AppDelegate.m
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
// AFNetworkingExampleAppDelegate.m
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
#import "AppDelegate.h"
|
||||||
|
#import "NearbySpotsViewController.h"
|
||||||
|
#import "AFURLCache.h"
|
||||||
|
|
||||||
|
@implementation AppDelegate
|
||||||
|
@synthesize window = _window;
|
||||||
|
@synthesize navigationController = _navigationController;
|
||||||
|
|
||||||
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||||
|
AFURLCache *URLCache = [[[AFURLCache alloc] initWithMemoryCapacity:1024 * 1024 diskCapacity:1024 * 1024 * 5 diskPath:[AFURLCache defaultCachePath]] autorelease];
|
||||||
|
[NSURLCache setSharedURLCache:URLCache];
|
||||||
|
|
||||||
|
UITableViewController *viewController = [[[NearbySpotsViewController alloc] init] autorelease];
|
||||||
|
self.navigationController = [[[UINavigationController alloc] initWithRootViewController:viewController] autorelease];
|
||||||
|
|
||||||
|
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
|
||||||
|
self.window.backgroundColor = [UIColor whiteColor];
|
||||||
|
self.window.rootViewController = self.navigationController;
|
||||||
|
[self.window makeKeyAndVisible];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[_window release];
|
||||||
|
[_navigationController release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// NearbySpotsViewController.h
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <CoreLocation/CoreLocation.h>
|
||||||
|
|
||||||
|
@interface NearbySpotsViewController : UITableViewController <CLLocationManagerDelegate> {
|
||||||
|
UIActivityIndicatorView *_activityIndicatorView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (readonly, nonatomic, retain) NSArray *nearbySpots;
|
||||||
|
@property (readonly, nonatomic, retain) CLLocationManager *locationManager;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
@ -0,0 +1,174 @@
|
||||||
|
// NearbySpotsViewController.m
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import "NearbySpotsViewController.h"
|
||||||
|
#import "Spot.h"
|
||||||
|
#import "SpotTableViewCell.h"
|
||||||
|
#import "TTTLocationFormatter.h"
|
||||||
|
|
||||||
|
@interface NearbySpotsViewController ()
|
||||||
|
@property (readwrite, nonatomic, retain) NSArray *nearbySpots;
|
||||||
|
@property (readwrite, nonatomic, retain) CLLocationManager *locationManager;
|
||||||
|
@property (readwrite, nonatomic, retain) UIActivityIndicatorView *activityIndicatorView;
|
||||||
|
|
||||||
|
- (void)loadSpotsForLocation:(CLLocation *)location;
|
||||||
|
- (void)refresh:(id)sender;
|
||||||
|
@end
|
||||||
|
|
||||||
|
static TTTLocationFormatter *__locationFormatter;
|
||||||
|
|
||||||
|
@implementation NearbySpotsViewController
|
||||||
|
@synthesize nearbySpots = _spots;
|
||||||
|
@synthesize locationManager = _locationManager;
|
||||||
|
@synthesize activityIndicatorView = _activityIndicatorView;
|
||||||
|
|
||||||
|
+ (void)initialize {
|
||||||
|
__locationFormatter = [[TTTLocationFormatter alloc] init];
|
||||||
|
[__locationFormatter setUnitSystem:TTTImperialSystem];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init {
|
||||||
|
self = [super init];
|
||||||
|
if (!self) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.nearbySpots = [NSArray array];
|
||||||
|
|
||||||
|
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
|
||||||
|
self.locationManager.delegate = self;
|
||||||
|
self.locationManager.distanceFilter = 80.0;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[_spots release];
|
||||||
|
[_locationManager release];
|
||||||
|
[_activityIndicatorView release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)loadSpotsForLocation:(CLLocation *)location {
|
||||||
|
[self.activityIndicatorView startAnimating];
|
||||||
|
self.navigationItem.rightBarButtonItem.enabled = NO;
|
||||||
|
|
||||||
|
[Spot spotsWithURLString:@"/spots/advanced_search" near:location parameters:[NSDictionary dictionaryWithObject:@"128" forKey:@"per_page"] withBlock:^(NSArray *records) {
|
||||||
|
self.nearbySpots = [records sortedArrayUsingComparator:^ NSComparisonResult(id obj1, id obj2) {
|
||||||
|
CLLocationDistance d1 = [[(Spot *)obj1 location] distanceFromLocation:location];
|
||||||
|
CLLocationDistance d2 = [[(Spot *)obj2 location] distanceFromLocation:location];
|
||||||
|
|
||||||
|
if (d1 < d2) {
|
||||||
|
return NSOrderedAscending;
|
||||||
|
} else if (d1 > d2) {
|
||||||
|
return NSOrderedDescending;
|
||||||
|
} else {
|
||||||
|
return NSOrderedSame;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
[self.tableView reloadData];
|
||||||
|
|
||||||
|
[self.activityIndicatorView stopAnimating];
|
||||||
|
self.navigationItem.rightBarButtonItem.enabled = YES;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UIViewController
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
[super viewDidLoad];
|
||||||
|
|
||||||
|
self.title = NSLocalizedString(@"Nearby Spots", nil);
|
||||||
|
|
||||||
|
self.activityIndicatorView = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite] autorelease];
|
||||||
|
self.activityIndicatorView.hidesWhenStopped = YES;
|
||||||
|
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:self.activityIndicatorView] autorelease];
|
||||||
|
|
||||||
|
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(refresh:)] autorelease];
|
||||||
|
self.navigationItem.rightBarButtonItem.enabled = NO;
|
||||||
|
|
||||||
|
[self.navigationController.navigationBar setTintColor:[UIColor darkGrayColor]];
|
||||||
|
|
||||||
|
[self.locationManager startUpdatingLocation];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidUnload {
|
||||||
|
[super viewDidUnload];
|
||||||
|
[self.locationManager stopUpdatingLocation];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - CLLocationManagerDelegate
|
||||||
|
|
||||||
|
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
|
||||||
|
[self loadSpotsForLocation:newLocation];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Actions
|
||||||
|
|
||||||
|
- (void)refresh:(id)sender {
|
||||||
|
self.nearbySpots = [NSArray array];
|
||||||
|
[self.tableView reloadData];
|
||||||
|
[[NSURLCache sharedURLCache] removeAllCachedResponses];
|
||||||
|
|
||||||
|
if (self.locationManager.location) {
|
||||||
|
[self loadSpotsForLocation:self.locationManager.location];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UITableViewDelegate
|
||||||
|
|
||||||
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||||
|
return [self.nearbySpots count];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
return 70.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
static NSString *CellIdentifier = @"Cell";
|
||||||
|
|
||||||
|
SpotTableViewCell *cell = (SpotTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
|
||||||
|
if (cell == nil) {
|
||||||
|
cell = [[[SpotTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
|
||||||
|
}
|
||||||
|
|
||||||
|
Spot *spot = [self.nearbySpots objectAtIndex:indexPath.row];
|
||||||
|
cell.textLabel.text = spot.name;
|
||||||
|
if (self.locationManager.location) {
|
||||||
|
cell.detailTextLabel.text = [__locationFormatter stringFromDistanceAndBearingFromLocation:self.locationManager.location toLocation:spot.location];
|
||||||
|
}
|
||||||
|
cell.imageURLString = spot.imageURLString;
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
45
AFNetworkingExample/Classes/Models/Spot.h
Normal file
45
AFNetworkingExample/Classes/Models/Spot.h
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Spot.h
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <CoreLocation/CoreLocation.h>
|
||||||
|
|
||||||
|
typedef void (^AFRecordsBlock)(NSArray *records);
|
||||||
|
|
||||||
|
@interface Spot : NSObject {
|
||||||
|
@private
|
||||||
|
NSString *_name;
|
||||||
|
NSString *_imageURLString;
|
||||||
|
NSNumber *_latitude;
|
||||||
|
NSNumber *_longitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (nonatomic, retain) NSString *name;
|
||||||
|
@property (nonatomic, retain) NSString *imageURLString;
|
||||||
|
@property (nonatomic, retain) NSNumber *latitude;
|
||||||
|
@property (nonatomic, retain) NSNumber *longitude;
|
||||||
|
@property (readonly) CLLocation *location;
|
||||||
|
|
||||||
|
- (id)initWithAttributes:(NSDictionary *)attributes;
|
||||||
|
+ (void)spotsWithURLString:(NSString *)urlString near:(CLLocation *)location parameters:(NSDictionary *)parameters withBlock:(AFRecordsBlock)block;
|
||||||
|
|
||||||
|
@end
|
||||||
79
AFNetworkingExample/Classes/Models/Spot.m
Normal file
79
AFNetworkingExample/Classes/Models/Spot.m
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
// Spot.m
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
#import "Spot.h"
|
||||||
|
|
||||||
|
#import "AFGowallaAPI.h"
|
||||||
|
|
||||||
|
@implementation Spot
|
||||||
|
@synthesize name = _name;
|
||||||
|
@synthesize imageURLString = _imageURLString;
|
||||||
|
@synthesize latitude = _latitude;
|
||||||
|
@synthesize longitude = _longitude;
|
||||||
|
@dynamic location;
|
||||||
|
|
||||||
|
- (id)initWithAttributes:(NSDictionary *)attributes {
|
||||||
|
self = [super init];
|
||||||
|
if (!self) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.name = [attributes valueForKeyPath:@"name"];
|
||||||
|
self.imageURLString = [attributes valueForKeyPath:@"image_url"];
|
||||||
|
self.latitude = [attributes valueForKeyPath:@"lat"];
|
||||||
|
self.longitude = [attributes valueForKeyPath:@"lng"];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[_name release];
|
||||||
|
[_imageURLString release];
|
||||||
|
[_latitude release];
|
||||||
|
[_longitude release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CLLocation *)location {
|
||||||
|
return [[[CLLocation alloc] initWithLatitude:[self.latitude doubleValue] longitude:[self.longitude doubleValue]] autorelease];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)spotsWithURLString:(NSString *)urlString near:(CLLocation *)location parameters:(NSDictionary *)parameters withBlock:(AFRecordsBlock)block {
|
||||||
|
NSDictionary *mutableParameters = [NSMutableDictionary dictionaryWithDictionary:parameters];
|
||||||
|
if (location) {
|
||||||
|
[mutableParameters setValue:[NSString stringWithFormat:@"%1.7f", location.coordinate.latitude] forKey:@"lat"];
|
||||||
|
[mutableParameters setValue:[NSString stringWithFormat:@"%1.7f", location.coordinate.longitude] forKey:@"lng"];
|
||||||
|
}
|
||||||
|
|
||||||
|
[AFGowallaAPI getPath:urlString parameters:mutableParameters callback:[AFHTTPOperationCallback callbackWithSuccess:^(NSURLRequest *request, NSHTTPURLResponse *response, NSDictionary *data) {
|
||||||
|
if (block) {
|
||||||
|
NSMutableArray *mutableRecords = [NSMutableArray array];
|
||||||
|
for (NSDictionary *attributes in [data valueForKeyPath:@"spots"]) {
|
||||||
|
Spot *spot = [[[Spot alloc] initWithAttributes:attributes] autorelease];
|
||||||
|
[mutableRecords addObject:spot];
|
||||||
|
}
|
||||||
|
|
||||||
|
block([NSArray arrayWithArray:mutableRecords]);
|
||||||
|
}
|
||||||
|
}]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
30
AFNetworkingExample/Classes/Views/SpotTableViewCell.h
Normal file
30
AFNetworkingExample/Classes/Views/SpotTableViewCell.h
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
// SpotTableViewCell.h
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import "AFImageRequest.h"
|
||||||
|
|
||||||
|
@interface SpotTableViewCell : UITableViewCell <AFImageRequester> {
|
||||||
|
NSString *_imageURLString;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
106
AFNetworkingExample/Classes/Views/SpotTableViewCell.m
Normal file
106
AFNetworkingExample/Classes/Views/SpotTableViewCell.m
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
// SpotTableViewCell.m
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import "SpotTableViewCell.h"
|
||||||
|
|
||||||
|
@implementation SpotTableViewCell
|
||||||
|
@synthesize imageURLString = _imageURLString;
|
||||||
|
|
||||||
|
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||||
|
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
|
||||||
|
if (!self) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.textLabel.textColor = [UIColor darkGrayColor];
|
||||||
|
self.textLabel.numberOfLines = 2;
|
||||||
|
|
||||||
|
self.detailTextLabel.textColor = [UIColor grayColor];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[_imageURLString release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setImageURLString:(NSString *)imageURLString {
|
||||||
|
[self setImageURLString:imageURLString options:AFImageRequestResize | AFImageCacheProcessedImage];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setImageURLString:(NSString *)imageURLString options:(AFImageRequestOptions)options {
|
||||||
|
if ([_imageURLString isEqual:imageURLString]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_imageURLString) {
|
||||||
|
self.imageView.image = [UIImage imageNamed:@"placeholder-stamp.png"];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self willChangeValueForKey:@"imageURLString"];
|
||||||
|
[_imageURLString release];
|
||||||
|
_imageURLString = [imageURLString copy];
|
||||||
|
[self didChangeValueForKey:@"imageURLString"];
|
||||||
|
|
||||||
|
if (imageURLString) {
|
||||||
|
[AFImageRequest requestImageWithURLString:self.imageURLString size:CGSizeMake(50.0f, 50.0f) options:options block:^(UIImage *image) {
|
||||||
|
if ([self.imageURLString isEqualToString:imageURLString]) {
|
||||||
|
BOOL needsLayout = self.imageView.image == nil;
|
||||||
|
self.imageView.image = image;
|
||||||
|
|
||||||
|
if (needsLayout) {
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UITableViewCell
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - UIView
|
||||||
|
|
||||||
|
- (void)layoutSubviews {
|
||||||
|
[super layoutSubviews];
|
||||||
|
|
||||||
|
CGRect imageViewFrame = self.imageView.frame;
|
||||||
|
CGRect textLabelFrame = self.textLabel.frame;
|
||||||
|
CGRect detailTextLabelFrame = self.detailTextLabel.frame;
|
||||||
|
|
||||||
|
imageViewFrame.origin.x = 10.0f;
|
||||||
|
imageViewFrame.origin.y = 10.0f;
|
||||||
|
imageViewFrame.size = CGSizeMake(50.0f, 50.0f);
|
||||||
|
|
||||||
|
textLabelFrame.origin.x = imageViewFrame.size.width + 30.0f;
|
||||||
|
detailTextLabelFrame.origin.x = textLabelFrame.origin.x;
|
||||||
|
|
||||||
|
textLabelFrame.size.width = 240.0f;
|
||||||
|
detailTextLabelFrame.size.width = textLabelFrame.size.width;
|
||||||
|
|
||||||
|
self.textLabel.frame = textLabelFrame;
|
||||||
|
self.detailTextLabel.frame = detailTextLabelFrame;
|
||||||
|
self.imageView.frame = imageViewFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
BIN
AFNetworkingExample/Images/placeholder-stamp.png
Normal file
BIN
AFNetworkingExample/Images/placeholder-stamp.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
BIN
AFNetworkingExample/Images/placeholder-stamp@2x.png
Normal file
BIN
AFNetworkingExample/Images/placeholder-stamp@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
36
AFNetworkingExample/Info.plist
Normal file
36
AFNetworkingExample/Info.plist
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>AFNetworking</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>${EXECUTABLE_NAME}</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string></string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.alamofire.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>${PRODUCT_NAME}</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
10
AFNetworkingExample/Prefix.pch
Normal file
10
AFNetworkingExample/Prefix.pch
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#import <Availability.h>
|
||||||
|
|
||||||
|
#ifndef __IPHONE_3_0
|
||||||
|
#warning "This project uses features only available in iPhone SDK 3.0 and later."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __OBJC__
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#endif
|
||||||
251
AFNetworkingExample/Vendor/JSONKit/JSONKit.h
vendored
Normal file
251
AFNetworkingExample/Vendor/JSONKit/JSONKit.h
vendored
Normal file
|
|
@ -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 <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#include <AvailabilityMacros.h>
|
||||||
|
|
||||||
|
#ifdef __OBJC__
|
||||||
|
#import <Foundation/NSArray.h>
|
||||||
|
#import <Foundation/NSData.h>
|
||||||
|
#import <Foundation/NSDictionary.h>
|
||||||
|
#import <Foundation/NSError.h>
|
||||||
|
#import <Foundation/NSObjCRuntime.h>
|
||||||
|
#import <Foundation/NSString.h>
|
||||||
|
#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
|
||||||
3011
AFNetworkingExample/Vendor/JSONKit/JSONKit.m
vendored
Normal file
3011
AFNetworkingExample/Vendor/JSONKit/JSONKit.m
vendored
Normal file
File diff suppressed because it is too large
Load diff
83
AFNetworkingExample/Vendor/TTT/TTTLocationFormatter.h
vendored
Normal file
83
AFNetworkingExample/Vendor/TTT/TTTLocationFormatter.h
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
// TTTLocationFormatter.h
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Mattt Thompson (http://mattt.me)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <CoreLocation/CoreLocation.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TTTNorthDirection,
|
||||||
|
TTTNortheastDirection,
|
||||||
|
TTTEastDirection,
|
||||||
|
TTTSoutheastDirection,
|
||||||
|
TTTSouthDirection,
|
||||||
|
TTTSouthwestDirection,
|
||||||
|
TTTWestDirection,
|
||||||
|
TTTNorthwestDirection,
|
||||||
|
} TTTLocationCardinalDirection;
|
||||||
|
|
||||||
|
extern TTTLocationCardinalDirection TTTLocationCardinalDirectionFromBearing(CLLocationDegrees bearing);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TTTCoordinateLatLngOrder = 0,
|
||||||
|
TTTCoordinateLngLatOrder,
|
||||||
|
} TTTLocationFormatterCoordinateOrder;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TTTBearingWordStyle = 0,
|
||||||
|
TTTBearingAbbreviationWordStyle,
|
||||||
|
TTTBearingNumericStyle,
|
||||||
|
} TTTLocationFormatterBearingStyle;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TTTMetricSystem = 0,
|
||||||
|
TTTImperialSystem,
|
||||||
|
} TTTLocationUnitSystem;
|
||||||
|
|
||||||
|
@interface TTTLocationFormatter : NSFormatter {
|
||||||
|
TTTLocationFormatterCoordinateOrder _coordinateOrder;
|
||||||
|
TTTLocationFormatterBearingStyle _bearingStyle;
|
||||||
|
TTTLocationUnitSystem _unitSystem;
|
||||||
|
NSNumberFormatter *_numberFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (readonly, nonatomic, retain) NSNumberFormatter *numberFormatter;
|
||||||
|
|
||||||
|
- (NSString *)stringFromCoordinate:(CLLocationCoordinate2D)coordinate;
|
||||||
|
- (NSString *)stringFromLocation:(CLLocation *)location;
|
||||||
|
- (NSString *)stringFromDistance:(CLLocationDistance)distance;
|
||||||
|
- (NSString *)stringFromBearing:(CLLocationDegrees)bearing;
|
||||||
|
- (NSString *)stringFromSpeed:(CLLocationSpeed)speed;
|
||||||
|
- (NSString *)stringFromDistanceFromLocation:(CLLocation *)originLocation toLocation:(CLLocation *)destinationLocation;
|
||||||
|
- (NSString *)stringFromBearingFromLocation:(CLLocation *)originLocation toLocation:(CLLocation *)destinationLocation;
|
||||||
|
- (NSString *)stringFromDistanceAndBearingFromLocation:(CLLocation *)originLocation toLocation:(CLLocation *)destinationLocation;
|
||||||
|
- (NSString *)stringFromVelocityFromLocation:(CLLocation *)originLocation toLocation:(CLLocation *)destinationLocation atSpeed:(CLLocationSpeed)speed;
|
||||||
|
|
||||||
|
- (TTTLocationFormatterCoordinateOrder)coordinateOrder;
|
||||||
|
- (void)setCoordinateOrder:(TTTLocationFormatterCoordinateOrder)coordinateOrder;
|
||||||
|
|
||||||
|
- (TTTLocationFormatterBearingStyle)bearingStyle;
|
||||||
|
- (void)setBearingStyle:(TTTLocationFormatterBearingStyle)bearingStyle;
|
||||||
|
|
||||||
|
- (TTTLocationUnitSystem)unitSystem;
|
||||||
|
- (void)setUnitSystem:(TTTLocationUnitSystem)unitSystem;
|
||||||
|
|
||||||
|
@end
|
||||||
299
AFNetworkingExample/Vendor/TTT/TTTLocationFormatter.m
vendored
Normal file
299
AFNetworkingExample/Vendor/TTT/TTTLocationFormatter.m
vendored
Normal file
|
|
@ -0,0 +1,299 @@
|
||||||
|
// TTTLocationFormatter.m
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Mattt Thompson (http://mattt.me)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import "TTTLocationFormatter.h"
|
||||||
|
|
||||||
|
static double const kTTTMetersToKilometersCoefficient = 0.001;
|
||||||
|
static double const kTTTMetersToFeetCoefficient = 3.2808399;
|
||||||
|
static double const kTTTMetersToYardsCoefficient = 1.0936133;
|
||||||
|
static double const kTTTMetersToMilesCoefficient = 0.000621371192;
|
||||||
|
|
||||||
|
static inline double CLLocationDistanceToKilometers(CLLocationDistance distance) {
|
||||||
|
return distance * kTTTMetersToKilometersCoefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double CLLocationDistanceToFeet(CLLocationDistance distance) {
|
||||||
|
return distance * kTTTMetersToFeetCoefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double CLLocationDistanceToYards(CLLocationDistance distance) {
|
||||||
|
return distance * kTTTMetersToYardsCoefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double CLLocationDistanceToMiles(CLLocationDistance distance) {
|
||||||
|
return distance * kTTTMetersToMilesCoefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
static inline double DEG2RAD(double degrees) {
|
||||||
|
return degrees * M_PI / 180;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline double RAD2DEG(double radians) {
|
||||||
|
return radians * 180 / M_PI;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline CLLocationDegrees CLLocationDegreesBearingBetweenCoordinates(CLLocationCoordinate2D originCoordinate, CLLocationCoordinate2D destinationCoordinate) {
|
||||||
|
double lat1 = DEG2RAD(originCoordinate.latitude);
|
||||||
|
double lon1 = DEG2RAD(originCoordinate.longitude);
|
||||||
|
double lat2 = DEG2RAD(destinationCoordinate.latitude);
|
||||||
|
double lon2 = DEG2RAD(destinationCoordinate.longitude);
|
||||||
|
|
||||||
|
double dLon = lon2 - lon1;
|
||||||
|
double y = sin(dLon) * cos(lat2);
|
||||||
|
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
|
||||||
|
double bearing = atan2(y, x) + (2 * M_PI);
|
||||||
|
|
||||||
|
// `atan2` works on a range of -π to 0 to π, so add on 2π and perform a modulo check
|
||||||
|
if (bearing > (2 * M_PI)) {
|
||||||
|
bearing = bearing - (2 * M_PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RAD2DEG(bearing);
|
||||||
|
}
|
||||||
|
|
||||||
|
TTTLocationCardinalDirection TTTLocationCardinalDirectionFromBearing(CLLocationDegrees bearing) {
|
||||||
|
if(bearing > 337.5) {
|
||||||
|
return TTTNorthDirection;
|
||||||
|
} else if(bearing > 292.5) {
|
||||||
|
return TTTNorthwestDirection;
|
||||||
|
} else if(bearing > 247.5) {
|
||||||
|
return TTTWestDirection;
|
||||||
|
} else if(bearing > 202.5) {
|
||||||
|
return TTTSouthwestDirection;
|
||||||
|
} else if(bearing > 157.5) {
|
||||||
|
return TTTSouthDirection;
|
||||||
|
} else if(bearing > 112.5) {
|
||||||
|
return TTTSoutheastDirection;
|
||||||
|
} else if(bearing > 67.5) {
|
||||||
|
return TTTEastDirection;
|
||||||
|
} else if(bearing > 22.5) {
|
||||||
|
return TTTNortheastDirection;
|
||||||
|
} else {
|
||||||
|
return TTTNorthDirection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
static double const kTTTMetersPerSecondToKilometersPerHourCoefficient = 3.6;
|
||||||
|
static double const kTTTMetersPerSecondToFeetPerSecondCoefficient = 3.2808399;
|
||||||
|
static double const kTTTMetersPerSecondToMilesPerHourCoefficient = 2.23693629;
|
||||||
|
|
||||||
|
static inline double CLLocationSpeedToKilometersPerHour(CLLocationSpeed speed) {
|
||||||
|
return speed * kTTTMetersPerSecondToKilometersPerHourCoefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double CLLocationSpeedToFeetPerSecond(CLLocationSpeed speed) {
|
||||||
|
return speed * kTTTMetersPerSecondToFeetPerSecondCoefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double CLLocationSpeedToMilesPerHour(CLLocationSpeed speed) {
|
||||||
|
return speed * kTTTMetersPerSecondToMilesPerHourCoefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@interface TTTLocationFormatter ()
|
||||||
|
@property (readwrite, nonatomic, assign) TTTLocationFormatterCoordinateOrder coordinateOrder;
|
||||||
|
@property (readwrite, nonatomic, assign) TTTLocationFormatterBearingStyle bearingStyle;
|
||||||
|
@property (readwrite, nonatomic, assign) TTTLocationUnitSystem unitSystem;
|
||||||
|
@property (readwrite, nonatomic, retain) NSNumberFormatter *numberFormatter;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation TTTLocationFormatter
|
||||||
|
@synthesize coordinateOrder = _coordinateOrder;
|
||||||
|
@synthesize bearingStyle = _bearingStyle;
|
||||||
|
@synthesize unitSystem = _unitSystem;
|
||||||
|
@synthesize numberFormatter = _numberFormatter;
|
||||||
|
|
||||||
|
- (id)init {
|
||||||
|
self = [super init];
|
||||||
|
if (!self) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.coordinateOrder = TTTCoordinateLatLngOrder;
|
||||||
|
self.bearingStyle = TTTBearingWordStyle;
|
||||||
|
self.unitSystem = TTTMetricSystem;
|
||||||
|
|
||||||
|
self.numberFormatter = [[[NSNumberFormatter alloc] init] autorelease];
|
||||||
|
[self.numberFormatter setLocale:[NSLocale currentLocale]];
|
||||||
|
[self.numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
|
||||||
|
[self.numberFormatter setMaximumSignificantDigits:2];
|
||||||
|
[self.numberFormatter setUsesSignificantDigits:YES];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)stringFromCoordinate:(CLLocationCoordinate2D)coordinate {
|
||||||
|
return [NSString stringWithFormat:NSLocalizedString(@"(%@, %@)", @"Coordinate format"), [self.numberFormatter stringFromNumber:[NSNumber numberWithDouble:coordinate.latitude]], [self.numberFormatter stringFromNumber:[NSNumber numberWithDouble:coordinate.longitude]], nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)stringFromLocation:(CLLocation *)location {
|
||||||
|
return [self stringFromCoordinate:location.coordinate];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)stringFromDistance:(CLLocationDistance)distance {
|
||||||
|
NSString *distanceString = nil;
|
||||||
|
NSString *unitString = nil;
|
||||||
|
|
||||||
|
switch (self.unitSystem) {
|
||||||
|
case TTTMetricSystem: {
|
||||||
|
double meterDistance = distance;
|
||||||
|
double kilometerDistance = CLLocationDistanceToKilometers(distance);
|
||||||
|
|
||||||
|
if (kilometerDistance > 1) {
|
||||||
|
distanceString = [self.numberFormatter stringFromNumber:[NSNumber numberWithDouble:kilometerDistance]];
|
||||||
|
unitString = NSLocalizedString(@"km", @"Kilometer Unit");
|
||||||
|
} else {
|
||||||
|
distanceString = [self.numberFormatter stringFromNumber:[NSNumber numberWithDouble:meterDistance]];
|
||||||
|
unitString = NSLocalizedString(@"m", @"Meter Unit");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TTTImperialSystem: {
|
||||||
|
double feetDistance = CLLocationDistanceToFeet(distance);
|
||||||
|
double yardDistance = CLLocationDistanceToYards(distance);
|
||||||
|
double milesDistance = CLLocationDistanceToMiles(distance);
|
||||||
|
|
||||||
|
if (feetDistance < 300) {
|
||||||
|
distanceString = [self.numberFormatter stringFromNumber:[NSNumber numberWithDouble:feetDistance]];
|
||||||
|
unitString = NSLocalizedString(@"ft", @"Feet Unit");
|
||||||
|
} else if (yardDistance < 500) {
|
||||||
|
distanceString = [self.numberFormatter stringFromNumber:[NSNumber numberWithDouble:yardDistance]];
|
||||||
|
unitString = NSLocalizedString(@"yds", @"Yard Unit");
|
||||||
|
} else {
|
||||||
|
distanceString = [self.numberFormatter stringFromNumber:[NSNumber numberWithDouble:milesDistance]];
|
||||||
|
unitString = (milesDistance > 1.0 && milesDistance < 1.1) ? NSLocalizedString(@"mile", @"Mile Unit (Singular)") : NSLocalizedString(@"miles", @"Mile Unit (Plural)");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [NSString stringWithFormat:NSLocalizedString(@"%@ %@", @"#{Distance} #{Unit}"), distanceString, unitString];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)stringFromBearing:(CLLocationDegrees)bearing {
|
||||||
|
switch (self.bearingStyle) {
|
||||||
|
case TTTBearingWordStyle:
|
||||||
|
switch (TTTLocationCardinalDirectionFromBearing(bearing)) {
|
||||||
|
case TTTNorthDirection:
|
||||||
|
return NSLocalizedString(@"North", @"North Direction");
|
||||||
|
case TTTNortheastDirection:
|
||||||
|
return NSLocalizedString(@"Northeast", @"Northeast Direction");
|
||||||
|
case TTTEastDirection:
|
||||||
|
return NSLocalizedString(@"East", @"East Direction");
|
||||||
|
case TTTSoutheastDirection:
|
||||||
|
return NSLocalizedString(@"Southeast", @"Southeast Direction");
|
||||||
|
case TTTSouthDirection:
|
||||||
|
return NSLocalizedString(@"South", @"South Direction");
|
||||||
|
case TTTSouthwestDirection:
|
||||||
|
return NSLocalizedString(@"Southwest", @"Southwest Direction");
|
||||||
|
case TTTWestDirection:
|
||||||
|
return NSLocalizedString(@"West", @"West Direction");
|
||||||
|
case TTTNorthwestDirection:
|
||||||
|
return NSLocalizedString(@"Northwest", @"Northwest Direction");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TTTBearingAbbreviationWordStyle:
|
||||||
|
switch (TTTLocationCardinalDirectionFromBearing(bearing)) {
|
||||||
|
case TTTNorthDirection:
|
||||||
|
return NSLocalizedString(@"N", @"North Direction Abbreviation");
|
||||||
|
case TTTNortheastDirection:
|
||||||
|
return NSLocalizedString(@"NE", @"Northeast Direction Abbreviation");
|
||||||
|
case TTTEastDirection:
|
||||||
|
return NSLocalizedString(@"E", @"East Direction Abbreviation");
|
||||||
|
case TTTSoutheastDirection:
|
||||||
|
return NSLocalizedString(@"SE", @"Southeast Direction Abbreviation");
|
||||||
|
case TTTSouthDirection:
|
||||||
|
return NSLocalizedString(@"S", @"South Direction Abbreviation");
|
||||||
|
case TTTSouthwestDirection:
|
||||||
|
return NSLocalizedString(@"SW", @"Southwest Direction Abbreviation");
|
||||||
|
case TTTWestDirection:
|
||||||
|
return NSLocalizedString(@"W", @"West Direction Abbreviation");
|
||||||
|
case TTTNorthwestDirection:
|
||||||
|
return NSLocalizedString(@"NW", @"Northwest Direction Abbreviation");;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TTTBearingNumericStyle:
|
||||||
|
return [[self.numberFormatter stringFromNumber:[NSNumber numberWithDouble:bearing]] stringByAppendingString:NSLocalizedString(@"°", @"Degrees Symbol")];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)stringFromSpeed:(CLLocationSpeed)speed {
|
||||||
|
NSString *speedString = nil;
|
||||||
|
NSString *unitString = nil;
|
||||||
|
|
||||||
|
switch (self.unitSystem) {
|
||||||
|
case TTTMetricSystem: {
|
||||||
|
double metersPerSecondSpeed = speed;
|
||||||
|
double kilometersPerHourSpeed = CLLocationSpeedToKilometersPerHour(speed);
|
||||||
|
|
||||||
|
if (kilometersPerHourSpeed > 1) {
|
||||||
|
speedString = [self.numberFormatter stringFromNumber:[NSNumber numberWithDouble:kilometersPerHourSpeed]];
|
||||||
|
unitString = NSLocalizedString(@"km/h", @"Kilometers Per Hour Unit");
|
||||||
|
} else {
|
||||||
|
speedString = [self.numberFormatter stringFromNumber:[NSNumber numberWithDouble:metersPerSecondSpeed]];
|
||||||
|
unitString = NSLocalizedString(@"m/s", @"Meters Per Second Unit");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TTTImperialSystem: {
|
||||||
|
double feetPerSecondSpeed = CLLocationSpeedToFeetPerSecond(speed);
|
||||||
|
double milesPerHourSpeed = CLLocationSpeedToMilesPerHour(speed);
|
||||||
|
|
||||||
|
if (milesPerHourSpeed > 1) {
|
||||||
|
speedString = [self.numberFormatter stringFromNumber:[NSNumber numberWithDouble:milesPerHourSpeed]];
|
||||||
|
unitString = NSLocalizedString(@"mph", @"Miles Per Hour Unit");
|
||||||
|
} else {
|
||||||
|
speedString = [self.numberFormatter stringFromNumber:[NSNumber numberWithDouble:feetPerSecondSpeed]];
|
||||||
|
unitString = NSLocalizedString(@"ft/s", @"Feet Per Second Unit");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [NSString stringWithFormat:NSLocalizedString(@"%@ %@", @"#{Speed} #{Unit}"), speedString, unitString];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)stringFromDistanceFromLocation:(CLLocation *)originLocation toLocation:(CLLocation *)destinationLocation {
|
||||||
|
return [self stringFromDistance:[destinationLocation distanceFromLocation:originLocation]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)stringFromBearingFromLocation:(CLLocation *)originLocation toLocation:(CLLocation *)destinationLocation {
|
||||||
|
return [self stringFromBearing:CLLocationDegreesBearingBetweenCoordinates(originLocation.coordinate, destinationLocation.coordinate)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)stringFromDistanceAndBearingFromLocation:(CLLocation *)originLocation toLocation:(CLLocation *)destinationLocation {
|
||||||
|
return [NSString stringWithFormat:NSLocalizedString(@"%@ %@", @"#{Dimensional Quantity} #{Direction}"), [self stringFromDistanceFromLocation:originLocation toLocation:destinationLocation], [self stringFromBearingFromLocation:originLocation toLocation:destinationLocation]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)stringFromVelocityFromLocation:(CLLocation *)originLocation toLocation:(CLLocation *)destinationLocation atSpeed:(CLLocationSpeed)speed {
|
||||||
|
return [NSString stringWithFormat:NSLocalizedString(@"%@ %@", @"#{Dimensional Quantity} #{Direction}"), [self stringFromSpeed:speed], [self stringFromBearingFromLocation:originLocation toLocation:destinationLocation]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
31
AFNetworkingExample/main.m
Normal file
31
AFNetworkingExample/main.m
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
// main.m
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
int retVal = UIApplicationMain(argc, argv, @"UIApplication", @"AppDelegate");
|
||||||
|
[pool release];
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
39
AFURLCache.h
Normal file
39
AFURLCache.h
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
// AFURLCache.h
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
extern NSString * AFURLCacheKeyForNSURLRequest(NSURLRequest *request);
|
||||||
|
|
||||||
|
@interface AFURLCache : NSURLCache {
|
||||||
|
@private
|
||||||
|
NSCountedSet *_cachedRequests;
|
||||||
|
NSMutableDictionary *_keyedCachedResponsesByRequest;
|
||||||
|
|
||||||
|
NSOperationQueue *_periodicMaintenanceOperationQueue;
|
||||||
|
NSOperation *_periodicMaintenanceOperation;
|
||||||
|
NSTimer *_periodicMaintenanceTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)defaultCachePath;
|
||||||
|
|
||||||
|
@end
|
||||||
159
AFURLCache.m
Normal file
159
AFURLCache.m
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
// AFURLCache.m
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import <CommonCrypto/CommonDigest.h>
|
||||||
|
#import "AFURLCache.h"
|
||||||
|
|
||||||
|
static const NSTimeInterval kAFURLCacheMaintenanceTimeInterval = 30.0;
|
||||||
|
|
||||||
|
NSString * AFURLCacheKeyForNSURLRequest(NSURLRequest *request) {
|
||||||
|
const char *str = [[[request URL] absoluteString] UTF8String];
|
||||||
|
unsigned char r[CC_MD5_DIGEST_LENGTH];
|
||||||
|
CC_MD5(str, strlen(str), r);
|
||||||
|
return [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
|
r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@interface AFURLCache ()
|
||||||
|
@property (nonatomic, retain) NSCountedSet *cachedRequests;
|
||||||
|
@property (nonatomic, retain) NSMutableDictionary *keyedCachedResponsesByRequest;
|
||||||
|
|
||||||
|
@property (nonatomic, retain) NSOperationQueue *periodicMaintenanceOperationQueue;
|
||||||
|
@property (nonatomic, retain) NSOperation *periodicMaintenanceOperation;
|
||||||
|
@property (nonatomic, retain) NSTimer *periodicMaintenanceTimer;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation AFURLCache
|
||||||
|
@synthesize cachedRequests = _cachedRequests;
|
||||||
|
@synthesize keyedCachedResponsesByRequest = _keyedCachedResponsesByRequest;
|
||||||
|
@synthesize periodicMaintenanceOperationQueue = _periodicMaintenanceOperationQueue;
|
||||||
|
@synthesize periodicMaintenanceOperation = _periodicMaintenanceOperation;
|
||||||
|
@synthesize periodicMaintenanceTimer = _periodicMaintenanceTimer;
|
||||||
|
|
||||||
|
+ (NSString *)defaultCachePath {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithMemoryCapacity:(NSUInteger)memoryCapacity diskCapacity:(NSUInteger)diskCapacity diskPath:(NSString *)path {
|
||||||
|
self = [super initWithMemoryCapacity:memoryCapacity diskCapacity:diskCapacity diskPath:path];
|
||||||
|
if (!self) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cachedRequests = [NSCountedSet setWithCapacity:200];
|
||||||
|
self.keyedCachedResponsesByRequest = [NSMutableDictionary dictionaryWithCapacity:200];
|
||||||
|
|
||||||
|
self.periodicMaintenanceOperationQueue = [[[NSOperationQueue alloc] init] autorelease];
|
||||||
|
[self.periodicMaintenanceOperationQueue setMaxConcurrentOperationCount:1];
|
||||||
|
self.periodicMaintenanceTimer = [[NSTimer scheduledTimerWithTimeInterval:kAFURLCacheMaintenanceTimeInterval target:self selector:@selector(periodicMaintenance) userInfo:nil repeats:YES] retain];
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sweepMemoryCache) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
|
||||||
|
[_cachedRequests release];
|
||||||
|
[_keyedCachedResponsesByRequest release];
|
||||||
|
|
||||||
|
[_periodicMaintenanceOperationQueue cancelAllOperations];
|
||||||
|
[_periodicMaintenanceOperationQueue release];
|
||||||
|
[_periodicMaintenanceOperation release];
|
||||||
|
|
||||||
|
[_periodicMaintenanceTimer invalidate];
|
||||||
|
_periodicMaintenanceTimer = nil;
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSURLCache
|
||||||
|
|
||||||
|
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {
|
||||||
|
NSString *cacheKey = AFURLCacheKeyForNSURLRequest(request);
|
||||||
|
NSCachedURLResponse *cachedResponse = [self.keyedCachedResponsesByRequest valueForKey:cacheKey];
|
||||||
|
if (cachedResponse) {
|
||||||
|
return cachedResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request {
|
||||||
|
NSString *cacheKey = AFURLCacheKeyForNSURLRequest(request);
|
||||||
|
[self.keyedCachedResponsesByRequest setObject:cachedResponse forKey:cacheKey];
|
||||||
|
[self.cachedRequests addObject:cacheKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeCachedResponseForRequest:(NSURLRequest *)request {
|
||||||
|
NSString *cacheKey = AFURLCacheKeyForNSURLRequest(request);
|
||||||
|
[self.keyedCachedResponsesByRequest removeObjectForKey:cacheKey];
|
||||||
|
[self.cachedRequests removeObject:cacheKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeAllCachedResponses {
|
||||||
|
[self.keyedCachedResponsesByRequest removeAllObjects];
|
||||||
|
[self.cachedRequests removeAllObjects];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)currentMemoryUsage {
|
||||||
|
return [[[self.keyedCachedResponsesByRequest allValues] valueForKeyPath:@"@sum.data.length"] integerValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Maintenance
|
||||||
|
|
||||||
|
- (void)periodicMaintenance {
|
||||||
|
[self.periodicMaintenanceOperation cancel];
|
||||||
|
self.periodicMaintenanceOperation = nil;
|
||||||
|
if ([self currentMemoryUsage] > [self memoryCapacity]) {
|
||||||
|
self.periodicMaintenanceOperation = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(sweepMemoryCache) object:nil] autorelease];
|
||||||
|
[self.periodicMaintenanceOperationQueue addOperation:self.periodicMaintenanceOperation];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sweepMemoryCache {
|
||||||
|
NSArray *sortedCachedRequests = [[self.cachedRequests allObjects] sortedArrayUsingComparator:^(id obj1, id obj2) {
|
||||||
|
NSUInteger count1 = [self.cachedRequests countForObject:obj1];
|
||||||
|
NSUInteger count2 = [self.cachedRequests countForObject:obj2];
|
||||||
|
|
||||||
|
if (count1 > count2) {
|
||||||
|
return NSOrderedDescending;
|
||||||
|
} else if (count1 < count2) {
|
||||||
|
return NSOrderedAscending;
|
||||||
|
} else {
|
||||||
|
return NSOrderedSame;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
NSUInteger memoryDeficit = [self currentMemoryUsage] - [self memoryCapacity];
|
||||||
|
NSString *cacheKey = nil;
|
||||||
|
NSEnumerator *enumerator = [sortedCachedRequests reverseObjectEnumerator];
|
||||||
|
while (memoryDeficit > 0 && (cacheKey = [enumerator nextObject])) {
|
||||||
|
NSCachedURLResponse *response = (NSCachedURLResponse *)[self.keyedCachedResponsesByRequest objectForKey:cacheKey];
|
||||||
|
memoryDeficit -= [[response data] length];
|
||||||
|
[self.keyedCachedResponsesByRequest removeObjectForKey:cacheKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cachedRequests = [NSCountedSet setWithArray:[self.keyedCachedResponsesByRequest allKeys]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
245
QHTTPOperation/QHTTPOperation.h
Normal file
245
QHTTPOperation/QHTTPOperation.h
Normal file
|
|
@ -0,0 +1,245 @@
|
||||||
|
/*
|
||||||
|
File: QHTTPOperation.h
|
||||||
|
|
||||||
|
Contains: An NSOperation that runs an HTTP request.
|
||||||
|
|
||||||
|
Written by: DTS
|
||||||
|
|
||||||
|
Copyright: Copyright (c) 2010 Apple Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
||||||
|
("Apple") in consideration of your agreement to the following
|
||||||
|
terms, and your use, installation, modification or
|
||||||
|
redistribution of this Apple software constitutes acceptance of
|
||||||
|
these terms. If you do not agree with these terms, please do
|
||||||
|
not use, install, modify or redistribute this Apple software.
|
||||||
|
|
||||||
|
In consideration of your agreement to abide by the following
|
||||||
|
terms, and subject to these terms, Apple grants you a personal,
|
||||||
|
non-exclusive license, under Apple's copyrights in this
|
||||||
|
original Apple software (the "Apple Software"), to use,
|
||||||
|
reproduce, modify and redistribute the Apple Software, with or
|
||||||
|
without modifications, in source and/or binary forms; provided
|
||||||
|
that if you redistribute the Apple Software in its entirety and
|
||||||
|
without modifications, you must retain this notice and the
|
||||||
|
following text and disclaimers in all such redistributions of
|
||||||
|
the Apple Software. Neither the name, trademarks, service marks
|
||||||
|
or logos of Apple Inc. may be used to endorse or promote
|
||||||
|
products derived from the Apple Software without specific prior
|
||||||
|
written permission from Apple. Except as expressly stated in
|
||||||
|
this notice, no other rights or licenses, express or implied,
|
||||||
|
are granted by Apple herein, including but not limited to any
|
||||||
|
patent rights that may be infringed by your derivative works or
|
||||||
|
by other works in which the Apple Software may be incorporated.
|
||||||
|
|
||||||
|
The Apple Software is provided by Apple on an "AS IS" basis.
|
||||||
|
APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
||||||
|
WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING
|
||||||
|
THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||||
|
COMBINATION WITH YOUR PRODUCTS.
|
||||||
|
|
||||||
|
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
||||||
|
INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY
|
||||||
|
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
|
||||||
|
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY
|
||||||
|
OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
|
||||||
|
OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "QRunLoopOperation.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
QHTTPOperation is a general purpose NSOperation that runs an HTTP request.
|
||||||
|
You initialise it with an HTTP request and then, when you run the operation,
|
||||||
|
it sends the request and gathers the response. It is quite a complex
|
||||||
|
object because it handles a wide variety of edge cases, but it's very
|
||||||
|
easy to use in simple cases:
|
||||||
|
|
||||||
|
1. create the operation with the URL you want to get
|
||||||
|
|
||||||
|
op = [[[QHTTPOperation alloc] initWithURL:url] autorelease];
|
||||||
|
|
||||||
|
2. set up any non-default parameters, for example, set which HTTP
|
||||||
|
content types are acceptable
|
||||||
|
|
||||||
|
op.acceptableContentTypes = [NSSet setWithObject:@"text/html"];
|
||||||
|
|
||||||
|
3. enqueue the operation
|
||||||
|
|
||||||
|
[queue addOperation:op];
|
||||||
|
|
||||||
|
4. finally, when the operation is done, use the lastResponse and
|
||||||
|
error properties to find out how things went
|
||||||
|
|
||||||
|
As mentioned above, QHTTPOperation is very general purpose. There are a
|
||||||
|
large number of configuration and result options available to you.
|
||||||
|
|
||||||
|
o You can specify a NSURLRequest rather than just a URL.
|
||||||
|
|
||||||
|
o You can configure the run loop and modes on which the NSURLConnection is
|
||||||
|
scheduled.
|
||||||
|
|
||||||
|
o You can specify what HTTP status codes and content types are OK.
|
||||||
|
|
||||||
|
o You can set an authentication delegate to handle authentication challenges.
|
||||||
|
|
||||||
|
o You can accumulate responses in memory or in an NSOutputStream.
|
||||||
|
|
||||||
|
o For in-memory responses, you can specify a default response size
|
||||||
|
(used to size the response buffer) and a maximum response size
|
||||||
|
(to prevent unbounded memory use).
|
||||||
|
|
||||||
|
o You can get at the last request and the last response, to track
|
||||||
|
redirects.
|
||||||
|
|
||||||
|
o There are a variety of funky debugging options to simulator errors
|
||||||
|
and delays.
|
||||||
|
|
||||||
|
Finally, it's perfectly reasonable to subclass QHTTPOperation to meet you
|
||||||
|
own specific needs. Specifically, it's common for the subclass to
|
||||||
|
override -connection:didReceiveResponse: in order to setup the output
|
||||||
|
stream based on the specific details of the response.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@protocol QHTTPOperationAuthenticationDelegate;
|
||||||
|
|
||||||
|
@interface QHTTPOperation : QRunLoopOperation /* <NSURLConnectionDelegate> */
|
||||||
|
{
|
||||||
|
NSURLRequest * _request;
|
||||||
|
NSIndexSet * _acceptableStatusCodes;
|
||||||
|
NSSet * _acceptableContentTypes;
|
||||||
|
id<QHTTPOperationAuthenticationDelegate> _authenticationDelegate;
|
||||||
|
NSOutputStream * _responseOutputStream;
|
||||||
|
NSUInteger _defaultResponseSize;
|
||||||
|
NSUInteger _maximumResponseSize;
|
||||||
|
NSURLConnection * _connection;
|
||||||
|
BOOL _firstData;
|
||||||
|
NSMutableData * _dataAccumulator;
|
||||||
|
NSURLRequest * _lastRequest;
|
||||||
|
NSHTTPURLResponse * _lastResponse;
|
||||||
|
NSData * _responseBody;
|
||||||
|
#if ! defined(NDEBUG)
|
||||||
|
NSError * _debugError;
|
||||||
|
NSTimeInterval _debugDelay;
|
||||||
|
NSTimer * _debugDelayTimer;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithRequest:(NSURLRequest *)request; // designated
|
||||||
|
- (id)initWithURL:(NSURL *)url; // convenience, calls +[NSURLRequest requestWithURL:]
|
||||||
|
|
||||||
|
// Things that are configured by the init method and can't be changed.
|
||||||
|
|
||||||
|
@property (copy, readonly) NSURLRequest * request;
|
||||||
|
@property (copy, readonly) NSURL * URL;
|
||||||
|
|
||||||
|
// Things you can configure before queuing the operation.
|
||||||
|
|
||||||
|
// runLoopThread and runLoopModes inherited from QRunLoopOperation
|
||||||
|
@property (copy, readwrite) NSIndexSet * acceptableStatusCodes; // default is nil, implying 200..299
|
||||||
|
@property (copy, readwrite) NSSet * acceptableContentTypes; // default is nil, implying anything is acceptable
|
||||||
|
@property (assign, readwrite) id<QHTTPOperationAuthenticationDelegate> authenticationDelegate;
|
||||||
|
|
||||||
|
#if ! defined(NDEBUG)
|
||||||
|
@property (copy, readwrite) NSError * debugError; // default is nil
|
||||||
|
@property (assign, readwrite) NSTimeInterval debugDelay; // default is none
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Things you can configure up to the point where you start receiving data.
|
||||||
|
// Typically you would change these in -connection:didReceiveResponse:, but
|
||||||
|
// it is possible to change them up to the point where -connection:didReceiveData:
|
||||||
|
// is called for the first time (that is, you could override -connection:didReceiveData:
|
||||||
|
// and change these before calling super).
|
||||||
|
|
||||||
|
// IMPORTANT: If you set a response stream, QHTTPOperation calls the response
|
||||||
|
// stream synchronously. This is fine for file and memory streams, but it would
|
||||||
|
// not work well for other types of streams (like a bound pair).
|
||||||
|
|
||||||
|
@property (retain, readwrite) NSOutputStream * responseOutputStream; // defaults to nil, which puts response into responseBody
|
||||||
|
@property (assign, readwrite) NSUInteger defaultResponseSize; // default is 1 MB, ignored if responseOutputStream is set
|
||||||
|
@property (assign, readwrite) NSUInteger maximumResponseSize; // default is 4 MB, ignored if responseOutputStream is set
|
||||||
|
// defaults are 1/4 of the above on embedded
|
||||||
|
|
||||||
|
// Things that are only meaningful after a response has been received;
|
||||||
|
|
||||||
|
@property (assign, readonly, getter=isStatusCodeAcceptable) BOOL statusCodeAcceptable;
|
||||||
|
@property (assign, readonly, getter=isContentTypeAcceptable) BOOL contentTypeAcceptable;
|
||||||
|
|
||||||
|
// Things that are only meaningful after the operation is finished.
|
||||||
|
|
||||||
|
// error property inherited from QRunLoopOperation
|
||||||
|
@property (copy, readonly) NSURLRequest * lastRequest;
|
||||||
|
@property (copy, readonly) NSHTTPURLResponse * lastResponse;
|
||||||
|
|
||||||
|
@property (copy, readonly) NSData * responseBody;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface QHTTPOperation (NSURLConnectionDelegate)
|
||||||
|
|
||||||
|
// QHTTPOperation implements all of these methods, so if you override them
|
||||||
|
// you must consider whether or not to call super.
|
||||||
|
//
|
||||||
|
// These will be called on the operation's run loop thread.
|
||||||
|
|
||||||
|
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace;
|
||||||
|
// Routes the request to the authentication delegate if it exists, otherwise
|
||||||
|
// just returns NO.
|
||||||
|
|
||||||
|
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
|
||||||
|
// Routes the request to the authentication delegate if it exists, otherwise
|
||||||
|
// just cancels the challenge.
|
||||||
|
|
||||||
|
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response;
|
||||||
|
// Latches the request and response in lastRequest and lastResponse.
|
||||||
|
|
||||||
|
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
|
||||||
|
// Latches the response in lastResponse.
|
||||||
|
|
||||||
|
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
|
||||||
|
// If this is the first chunk of data, it decides whether the data is going to be
|
||||||
|
// routed to memory (responseBody) or a stream (responseOutputStream) and makes the
|
||||||
|
// appropriate preparations. For this and subsequent data it then actually shuffles
|
||||||
|
// the data to its destination.
|
||||||
|
|
||||||
|
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
|
||||||
|
// Completes the operation with either no error (if the response status code is acceptable)
|
||||||
|
// or an error (otherwise).
|
||||||
|
|
||||||
|
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
|
||||||
|
// Completes the operation with the error.
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol QHTTPOperationAuthenticationDelegate <NSObject>
|
||||||
|
@required
|
||||||
|
|
||||||
|
// These are called on the operation's run loop thread and have the same semantics as their
|
||||||
|
// NSURLConnection equivalents. It's important to realise that there is no
|
||||||
|
// didCancelAuthenticationChallenge callback (because NSURLConnection doesn't issue one to us).
|
||||||
|
// Rather, an authentication delegate is expected to observe the operation and cancel itself
|
||||||
|
// if the operation completes while the challenge is running.
|
||||||
|
|
||||||
|
- (BOOL)httpOperation:(QHTTPOperation *)operation canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace;
|
||||||
|
- (void)httpOperation:(QHTTPOperation *)operation didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
extern NSString * kQHTTPOperationErrorDomain;
|
||||||
|
|
||||||
|
// positive error codes are HTML status codes (when they are not allowed via acceptableStatusCodes)
|
||||||
|
//
|
||||||
|
// 0 is, of course, not a valid error code
|
||||||
|
//
|
||||||
|
// negative error codes are errors from the module
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kQHTTPOperationErrorResponseTooLarge = -1,
|
||||||
|
kQHTTPOperationErrorOnOutputStream = -2,
|
||||||
|
kQHTTPOperationErrorBadContentType = -3
|
||||||
|
};
|
||||||
653
QHTTPOperation/QHTTPOperation.m
Normal file
653
QHTTPOperation/QHTTPOperation.m
Normal file
|
|
@ -0,0 +1,653 @@
|
||||||
|
/*
|
||||||
|
File: QHTTPOperation.m
|
||||||
|
|
||||||
|
Contains: An NSOperation that runs an HTTP request.
|
||||||
|
|
||||||
|
Written by: DTS
|
||||||
|
|
||||||
|
Copyright: Copyright (c) 2010 Apple Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
||||||
|
("Apple") in consideration of your agreement to the following
|
||||||
|
terms, and your use, installation, modification or
|
||||||
|
redistribution of this Apple software constitutes acceptance of
|
||||||
|
these terms. If you do not agree with these terms, please do
|
||||||
|
not use, install, modify or redistribute this Apple software.
|
||||||
|
|
||||||
|
In consideration of your agreement to abide by the following
|
||||||
|
terms, and subject to these terms, Apple grants you a personal,
|
||||||
|
non-exclusive license, under Apple's copyrights in this
|
||||||
|
original Apple software (the "Apple Software"), to use,
|
||||||
|
reproduce, modify and redistribute the Apple Software, with or
|
||||||
|
without modifications, in source and/or binary forms; provided
|
||||||
|
that if you redistribute the Apple Software in its entirety and
|
||||||
|
without modifications, you must retain this notice and the
|
||||||
|
following text and disclaimers in all such redistributions of
|
||||||
|
the Apple Software. Neither the name, trademarks, service marks
|
||||||
|
or logos of Apple Inc. may be used to endorse or promote
|
||||||
|
products derived from the Apple Software without specific prior
|
||||||
|
written permission from Apple. Except as expressly stated in
|
||||||
|
this notice, no other rights or licenses, express or implied,
|
||||||
|
are granted by Apple herein, including but not limited to any
|
||||||
|
patent rights that may be infringed by your derivative works or
|
||||||
|
by other works in which the Apple Software may be incorporated.
|
||||||
|
|
||||||
|
The Apple Software is provided by Apple on an "AS IS" basis.
|
||||||
|
APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
||||||
|
WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING
|
||||||
|
THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||||
|
COMBINATION WITH YOUR PRODUCTS.
|
||||||
|
|
||||||
|
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
||||||
|
INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY
|
||||||
|
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
|
||||||
|
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY
|
||||||
|
OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
|
||||||
|
OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "QHTTPOperation.h"
|
||||||
|
|
||||||
|
@interface QHTTPOperation ()
|
||||||
|
|
||||||
|
// Read/write versions of public properties
|
||||||
|
|
||||||
|
@property (copy, readwrite) NSURLRequest * lastRequest;
|
||||||
|
@property (copy, readwrite) NSHTTPURLResponse * lastResponse;
|
||||||
|
|
||||||
|
// Internal properties
|
||||||
|
|
||||||
|
@property (retain, readwrite) NSURLConnection * connection;
|
||||||
|
@property (assign, readwrite) BOOL firstData;
|
||||||
|
@property (retain, readwrite) NSMutableData * dataAccumulator;
|
||||||
|
|
||||||
|
#if ! defined(NDEBUG)
|
||||||
|
@property (retain, readwrite) NSTimer * debugDelayTimer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation QHTTPOperation
|
||||||
|
|
||||||
|
#pragma mark * Initialise and finalise
|
||||||
|
|
||||||
|
- (id)initWithRequest:(NSURLRequest *)request
|
||||||
|
// See comment in header.
|
||||||
|
{
|
||||||
|
// any thread
|
||||||
|
assert(request != nil);
|
||||||
|
assert([request URL] != nil);
|
||||||
|
// Because we require an NSHTTPURLResponse, we only support HTTP and HTTPS URLs.
|
||||||
|
assert([[[[request URL] scheme] lowercaseString] isEqual:@"http"] || [[[[request URL] scheme] lowercaseString] isEqual:@"https"]);
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil) {
|
||||||
|
#if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
|
||||||
|
static const NSUInteger kPlatformReductionFactor = 4;
|
||||||
|
#else
|
||||||
|
static const NSUInteger kPlatformReductionFactor = 1;
|
||||||
|
#endif
|
||||||
|
self->_request = [request copy];
|
||||||
|
self->_defaultResponseSize = 1 * 1024 * 1024 / kPlatformReductionFactor;
|
||||||
|
self->_maximumResponseSize = 4 * 1024 * 1024 / kPlatformReductionFactor;
|
||||||
|
self->_firstData = YES;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithURL:(NSURL *)url
|
||||||
|
// See comment in header.
|
||||||
|
{
|
||||||
|
assert(url != nil);
|
||||||
|
return [self initWithRequest:[NSURLRequest requestWithURL:url]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
#if ! defined(NDEBUG)
|
||||||
|
[self->_debugError release];
|
||||||
|
[self->_debugDelayTimer invalidate];
|
||||||
|
[self->_debugDelayTimer release];
|
||||||
|
#endif
|
||||||
|
// any thread
|
||||||
|
[self->_request release];
|
||||||
|
[self->_acceptableStatusCodes release];
|
||||||
|
[self->_acceptableContentTypes release];
|
||||||
|
[self->_responseOutputStream release];
|
||||||
|
assert(self->_connection == nil); // should have been shut down by now
|
||||||
|
[self->_dataAccumulator release];
|
||||||
|
[self->_lastRequest release];
|
||||||
|
[self->_lastResponse release];
|
||||||
|
[self->_responseBody release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark * Properties
|
||||||
|
|
||||||
|
// We write our own settings for many properties because we want to bounce
|
||||||
|
// sets that occur in the wrong state. And, given that we've written the
|
||||||
|
// setter anyway, we also avoid KVO notifications when the value doesn't change.
|
||||||
|
|
||||||
|
@synthesize request = _request;
|
||||||
|
|
||||||
|
@synthesize authenticationDelegate = _authenticationDelegate;
|
||||||
|
|
||||||
|
+ (BOOL)automaticallyNotifiesObserversOfAuthenticationDelegate
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<QHTTPOperationAuthenticationDelegate>)authenticationDelegate
|
||||||
|
{
|
||||||
|
return self->_authenticationDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAuthenticationDelegate:(id<QHTTPOperationAuthenticationDelegate>)newValue
|
||||||
|
{
|
||||||
|
if (self.state != kQRunLoopOperationStateInited) {
|
||||||
|
assert(NO);
|
||||||
|
} else {
|
||||||
|
if (newValue != self->_authenticationDelegate) {
|
||||||
|
[self willChangeValueForKey:@"authenticationDelegate"];
|
||||||
|
self->_authenticationDelegate = newValue;
|
||||||
|
[self didChangeValueForKey:@"authenticationDelegate"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize acceptableStatusCodes = _acceptableStatusCodes;
|
||||||
|
|
||||||
|
+ (BOOL)automaticallyNotifiesObserversOfAcceptableStatusCodes
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSIndexSet *)acceptableStatusCodes
|
||||||
|
{
|
||||||
|
return [[self->_acceptableStatusCodes retain] autorelease];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAcceptableStatusCodes:(NSIndexSet *)newValue
|
||||||
|
{
|
||||||
|
if (self.state != kQRunLoopOperationStateInited) {
|
||||||
|
assert(NO);
|
||||||
|
} else {
|
||||||
|
if (newValue != self->_acceptableStatusCodes) {
|
||||||
|
[self willChangeValueForKey:@"acceptableStatusCodes"];
|
||||||
|
[self->_acceptableStatusCodes autorelease];
|
||||||
|
self->_acceptableStatusCodes = [newValue copy];
|
||||||
|
[self didChangeValueForKey:@"acceptableStatusCodes"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize acceptableContentTypes = _acceptableContentTypes;
|
||||||
|
|
||||||
|
+ (BOOL)automaticallyNotifiesObserversOfAcceptableContentTypes
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSSet *)acceptableContentTypes
|
||||||
|
{
|
||||||
|
return [[self->_acceptableContentTypes retain] autorelease];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAcceptableContentTypes:(NSSet *)newValue
|
||||||
|
{
|
||||||
|
if (self.state != kQRunLoopOperationStateInited) {
|
||||||
|
assert(NO);
|
||||||
|
} else {
|
||||||
|
if (newValue != self->_acceptableContentTypes) {
|
||||||
|
[self willChangeValueForKey:@"acceptableContentTypes"];
|
||||||
|
[self->_acceptableContentTypes autorelease];
|
||||||
|
self->_acceptableContentTypes = [newValue copy];
|
||||||
|
[self didChangeValueForKey:@"acceptableContentTypes"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize responseOutputStream = _responseOutputStream;
|
||||||
|
|
||||||
|
+ (BOOL)automaticallyNotifiesObserversOfResponseOutputStream
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSOutputStream *)responseOutputStream
|
||||||
|
{
|
||||||
|
return [[self->_responseOutputStream retain] autorelease];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setResponseOutputStream:(NSOutputStream *)newValue
|
||||||
|
{
|
||||||
|
if (self.dataAccumulator != nil) {
|
||||||
|
assert(NO);
|
||||||
|
} else {
|
||||||
|
if (newValue != self->_responseOutputStream) {
|
||||||
|
[self willChangeValueForKey:@"responseOutputStream"];
|
||||||
|
[self->_responseOutputStream autorelease];
|
||||||
|
self->_responseOutputStream = [newValue retain];
|
||||||
|
[self didChangeValueForKey:@"responseOutputStream"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize defaultResponseSize = _defaultResponseSize;
|
||||||
|
|
||||||
|
+ (BOOL)automaticallyNotifiesObserversOfDefaultResponseSize
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)defaultResponseSize
|
||||||
|
{
|
||||||
|
return self->_defaultResponseSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDefaultResponseSize:(NSUInteger)newValue
|
||||||
|
{
|
||||||
|
if (self.dataAccumulator != nil) {
|
||||||
|
assert(NO);
|
||||||
|
} else {
|
||||||
|
if (newValue != self->_defaultResponseSize) {
|
||||||
|
[self willChangeValueForKey:@"defaultResponseSize"];
|
||||||
|
self->_defaultResponseSize = newValue;
|
||||||
|
[self didChangeValueForKey:@"defaultResponseSize"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize maximumResponseSize = _maximumResponseSize;
|
||||||
|
|
||||||
|
+ (BOOL)automaticallyNotifiesObserversOfMaximumResponseSize
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)maximumResponseSize
|
||||||
|
{
|
||||||
|
return self->_maximumResponseSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMaximumResponseSize:(NSUInteger)newValue
|
||||||
|
{
|
||||||
|
if (self.dataAccumulator != nil) {
|
||||||
|
assert(NO);
|
||||||
|
} else {
|
||||||
|
if (newValue != self->_maximumResponseSize) {
|
||||||
|
[self willChangeValueForKey:@"maximumResponseSize"];
|
||||||
|
self->_maximumResponseSize = newValue;
|
||||||
|
[self didChangeValueForKey:@"maximumResponseSize"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize lastRequest = _lastRequest;
|
||||||
|
@synthesize lastResponse = _lastResponse;
|
||||||
|
@synthesize responseBody = _responseBody;
|
||||||
|
|
||||||
|
@synthesize connection = _connection;
|
||||||
|
@synthesize firstData = _firstData;
|
||||||
|
@synthesize dataAccumulator = _dataAccumulator;
|
||||||
|
|
||||||
|
- (NSURL *)URL
|
||||||
|
{
|
||||||
|
return [self.request URL];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isStatusCodeAcceptable
|
||||||
|
{
|
||||||
|
NSIndexSet * acceptableStatusCodes;
|
||||||
|
NSInteger statusCode;
|
||||||
|
|
||||||
|
assert(self.lastResponse != nil);
|
||||||
|
|
||||||
|
acceptableStatusCodes = self.acceptableStatusCodes;
|
||||||
|
if (acceptableStatusCodes == nil) {
|
||||||
|
acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
|
||||||
|
}
|
||||||
|
assert(acceptableStatusCodes != nil);
|
||||||
|
|
||||||
|
statusCode = [self.lastResponse statusCode];
|
||||||
|
return (statusCode >= 0) && [acceptableStatusCodes containsIndex: (NSUInteger) statusCode];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isContentTypeAcceptable
|
||||||
|
{
|
||||||
|
NSString * contentType;
|
||||||
|
|
||||||
|
assert(self.lastResponse != nil);
|
||||||
|
contentType = [self.lastResponse MIMEType];
|
||||||
|
return (self.acceptableContentTypes == nil) || ((contentType != nil) && [self.acceptableContentTypes containsObject:contentType]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark * Start and finish overrides
|
||||||
|
|
||||||
|
- (void)operationDidStart
|
||||||
|
// Called by QRunLoopOperation when the operation starts. This kicks of an
|
||||||
|
// asynchronous NSURLConnection.
|
||||||
|
{
|
||||||
|
assert(self.isActualRunLoopThread);
|
||||||
|
assert(self.state == kQRunLoopOperationStateExecuting);
|
||||||
|
|
||||||
|
assert(self.defaultResponseSize > 0);
|
||||||
|
assert(self.maximumResponseSize > 0);
|
||||||
|
assert(self.defaultResponseSize <= self.maximumResponseSize);
|
||||||
|
|
||||||
|
assert(self.request != nil);
|
||||||
|
|
||||||
|
// If a debug error is set, apply that error rather than running the connection.
|
||||||
|
|
||||||
|
#if ! defined(NDEBUG)
|
||||||
|
if (self.debugError != nil) {
|
||||||
|
[self finishWithError:self.debugError];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Create a connection that's scheduled in the required run loop modes.
|
||||||
|
|
||||||
|
assert(self.connection == nil);
|
||||||
|
self.connection = [[[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO] autorelease];
|
||||||
|
assert(self.connection != nil);
|
||||||
|
|
||||||
|
for (NSString * mode in self.actualRunLoopModes) {
|
||||||
|
[self.connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:mode];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self.connection start];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)operationWillFinish
|
||||||
|
// Called by QRunLoopOperation when the operation has finished. We
|
||||||
|
// do various bits of tidying up.
|
||||||
|
{
|
||||||
|
assert(self.isActualRunLoopThread);
|
||||||
|
assert(self.state == kQRunLoopOperationStateExecuting);
|
||||||
|
|
||||||
|
// It is possible to hit this state of the operation is cancelled while
|
||||||
|
// the debugDelayTimer is running. In that case, hey, we'll just accept
|
||||||
|
// the inevitable and finish rather than trying anything else clever.
|
||||||
|
|
||||||
|
#if ! defined(NDEBUG)
|
||||||
|
if (self.debugDelayTimer != nil) {
|
||||||
|
[self.debugDelayTimer invalidate];
|
||||||
|
self.debugDelayTimer = nil;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[self.connection cancel];
|
||||||
|
self.connection = nil;
|
||||||
|
|
||||||
|
// If we have an output stream, close it at this point. We might never
|
||||||
|
// have actually opened this stream but, AFAICT, closing an unopened stream
|
||||||
|
// doesn't hurt.
|
||||||
|
|
||||||
|
if (self.responseOutputStream != nil) {
|
||||||
|
[self.responseOutputStream close];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)finishWithError:(NSError *)error
|
||||||
|
// We override -finishWithError: just so we can handle our debug delay.
|
||||||
|
{
|
||||||
|
// If a debug delay was set, don't finish now but rather start the debug delay timer
|
||||||
|
// and have it do the actual finish. We clear self.debugDelay so that the next
|
||||||
|
// time this code runs its doesn't do this again.
|
||||||
|
//
|
||||||
|
// We only do this in the non-cancellation case. In the cancellation case, we
|
||||||
|
// just stop immediately.
|
||||||
|
|
||||||
|
#if ! defined(NDEBUG)
|
||||||
|
if (self.debugDelay > 0.0) {
|
||||||
|
if ( (error != nil) && [[error domain] isEqual:NSCocoaErrorDomain] && ([error code] == NSUserCancelledError) ) {
|
||||||
|
self.debugDelay = 0.0;
|
||||||
|
} else {
|
||||||
|
assert(self.debugDelayTimer == nil);
|
||||||
|
self.debugDelayTimer = [NSTimer timerWithTimeInterval:self.debugDelay target:self selector:@selector(debugDelayTimerDone:) userInfo:error repeats:NO];
|
||||||
|
assert(self.debugDelayTimer != nil);
|
||||||
|
for (NSString * mode in self.actualRunLoopModes) {
|
||||||
|
[[NSRunLoop currentRunLoop] addTimer:self.debugDelayTimer forMode:mode];
|
||||||
|
}
|
||||||
|
self.debugDelay = 0.0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[super finishWithError:error];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ! defined(NDEBUG)
|
||||||
|
|
||||||
|
@synthesize debugError = _debugError;
|
||||||
|
@synthesize debugDelay = _debugDelay;
|
||||||
|
@synthesize debugDelayTimer = _debugDelayTimer;
|
||||||
|
|
||||||
|
- (void)debugDelayTimerDone:(NSTimer *)timer
|
||||||
|
{
|
||||||
|
NSError * error;
|
||||||
|
|
||||||
|
assert(timer == self.debugDelayTimer);
|
||||||
|
|
||||||
|
error = [[[timer userInfo] retain] autorelease];
|
||||||
|
assert( (error == nil) || [error isKindOfClass:[NSError class]] );
|
||||||
|
|
||||||
|
[self.debugDelayTimer invalidate];
|
||||||
|
self.debugDelayTimer = nil;
|
||||||
|
|
||||||
|
[self finishWithError:error];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma mark * NSURLConnection delegate callbacks
|
||||||
|
|
||||||
|
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
|
||||||
|
// See comment in header.
|
||||||
|
{
|
||||||
|
BOOL result;
|
||||||
|
|
||||||
|
assert(self.isActualRunLoopThread);
|
||||||
|
assert(connection == self.connection);
|
||||||
|
#pragma unused(connection)
|
||||||
|
assert(protectionSpace != nil);
|
||||||
|
#pragma unused(protectionSpace)
|
||||||
|
|
||||||
|
result = NO;
|
||||||
|
if (self.authenticationDelegate != nil) {
|
||||||
|
result = [self.authenticationDelegate httpOperation:self canAuthenticateAgainstProtectionSpace:protectionSpace];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
|
||||||
|
// See comment in header.
|
||||||
|
{
|
||||||
|
assert(self.isActualRunLoopThread);
|
||||||
|
assert(connection == self.connection);
|
||||||
|
#pragma unused(connection)
|
||||||
|
assert(challenge != nil);
|
||||||
|
#pragma unused(challenge)
|
||||||
|
|
||||||
|
if (self.authenticationDelegate != nil) {
|
||||||
|
[self.authenticationDelegate httpOperation:self didReceiveAuthenticationChallenge:challenge];
|
||||||
|
} else {
|
||||||
|
if ( [challenge previousFailureCount] == 0 ) {
|
||||||
|
[[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
|
||||||
|
} else {
|
||||||
|
[[challenge sender] cancelAuthenticationChallenge:challenge];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response
|
||||||
|
// See comment in header.
|
||||||
|
{
|
||||||
|
assert(self.isActualRunLoopThread);
|
||||||
|
assert(connection == self.connection);
|
||||||
|
#pragma unused(connection)
|
||||||
|
assert( (response == nil) || [response isKindOfClass:[NSHTTPURLResponse class]] );
|
||||||
|
|
||||||
|
self.lastRequest = request;
|
||||||
|
self.lastResponse = (NSHTTPURLResponse *) response;
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
|
||||||
|
// See comment in header.
|
||||||
|
{
|
||||||
|
assert(self.isActualRunLoopThread);
|
||||||
|
assert(connection == self.connection);
|
||||||
|
#pragma unused(connection)
|
||||||
|
assert([response isKindOfClass:[NSHTTPURLResponse class]]);
|
||||||
|
|
||||||
|
self.lastResponse = (NSHTTPURLResponse *) response;
|
||||||
|
|
||||||
|
// We don't check the status code here because we want to give the client an opportunity
|
||||||
|
// to get the data of the error message. Perhaps we /should/ check the content type
|
||||||
|
// here, but I'm not sure whether that's the right thing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
|
||||||
|
// See comment in header.
|
||||||
|
{
|
||||||
|
BOOL success;
|
||||||
|
|
||||||
|
assert(self.isActualRunLoopThread);
|
||||||
|
assert(connection == self.connection);
|
||||||
|
#pragma unused(connection)
|
||||||
|
assert(data != nil);
|
||||||
|
|
||||||
|
// If we don't yet have a destination for the data, calculate one. Note that, even
|
||||||
|
// if there is an output stream, we don't use it for error responses.
|
||||||
|
|
||||||
|
success = YES;
|
||||||
|
if (self.firstData) {
|
||||||
|
assert(self.dataAccumulator == nil);
|
||||||
|
|
||||||
|
if ( (self.responseOutputStream == nil) || ! self.isStatusCodeAcceptable ) {
|
||||||
|
long long length;
|
||||||
|
|
||||||
|
assert(self.dataAccumulator == nil);
|
||||||
|
|
||||||
|
length = [self.lastResponse expectedContentLength];
|
||||||
|
if (length == NSURLResponseUnknownLength) {
|
||||||
|
length = self.defaultResponseSize;
|
||||||
|
}
|
||||||
|
if (length <= (long long) self.maximumResponseSize) {
|
||||||
|
self.dataAccumulator = [NSMutableData dataWithCapacity:(NSUInteger)length];
|
||||||
|
} else {
|
||||||
|
[self finishWithError:[NSError errorWithDomain:kQHTTPOperationErrorDomain code:kQHTTPOperationErrorResponseTooLarge userInfo:nil]];
|
||||||
|
success = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the data is going to an output stream, open it.
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
if (self.dataAccumulator == nil) {
|
||||||
|
assert(self.responseOutputStream != nil);
|
||||||
|
[self.responseOutputStream open];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.firstData = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the data to its destination.
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
if (self.dataAccumulator != nil) {
|
||||||
|
if ( ([self.dataAccumulator length] + [data length]) <= self.maximumResponseSize ) {
|
||||||
|
[self.dataAccumulator appendData:data];
|
||||||
|
} else {
|
||||||
|
[self finishWithError:[NSError errorWithDomain:kQHTTPOperationErrorDomain code:kQHTTPOperationErrorResponseTooLarge userInfo:nil]];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NSUInteger dataOffset;
|
||||||
|
NSUInteger dataLength;
|
||||||
|
const uint8_t * dataPtr;
|
||||||
|
NSError * error;
|
||||||
|
NSInteger bytesWritten;
|
||||||
|
|
||||||
|
assert(self.responseOutputStream != nil);
|
||||||
|
|
||||||
|
dataOffset = 0;
|
||||||
|
dataLength = [data length];
|
||||||
|
dataPtr = [data bytes];
|
||||||
|
error = nil;
|
||||||
|
do {
|
||||||
|
if (dataOffset == dataLength) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytesWritten = [self.responseOutputStream write:&dataPtr[dataOffset] maxLength:dataLength - dataOffset];
|
||||||
|
if (bytesWritten <= 0) {
|
||||||
|
error = [self.responseOutputStream streamError];
|
||||||
|
if (error == nil) {
|
||||||
|
error = [NSError errorWithDomain:kQHTTPOperationErrorDomain code:kQHTTPOperationErrorOnOutputStream userInfo:nil];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
dataOffset += bytesWritten;
|
||||||
|
}
|
||||||
|
} while (YES);
|
||||||
|
|
||||||
|
if (error != nil) {
|
||||||
|
[self finishWithError:error];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
|
||||||
|
// See comment in header.
|
||||||
|
{
|
||||||
|
assert(self.isActualRunLoopThread);
|
||||||
|
assert(connection == self.connection);
|
||||||
|
#pragma unused(connection)
|
||||||
|
|
||||||
|
assert(self.lastResponse != nil);
|
||||||
|
|
||||||
|
// Swap the data accumulator over to the response data so that we don't trigger a copy.
|
||||||
|
|
||||||
|
assert(self->_responseBody == nil);
|
||||||
|
self->_responseBody = self->_dataAccumulator;
|
||||||
|
self->_dataAccumulator = nil;
|
||||||
|
|
||||||
|
// Because we fill out _dataAccumulator lazily, an empty body will leave _dataAccumulator
|
||||||
|
// set to nil. That's not what our clients expect, so we fix it here.
|
||||||
|
|
||||||
|
if (self->_responseBody == nil) {
|
||||||
|
self->_responseBody = [[NSData alloc] init];
|
||||||
|
assert(self->_responseBody != nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! self.isStatusCodeAcceptable ) {
|
||||||
|
[self finishWithError:[NSError errorWithDomain:kQHTTPOperationErrorDomain code:self.lastResponse.statusCode userInfo:nil]];
|
||||||
|
} else if ( ! self.isContentTypeAcceptable ) {
|
||||||
|
[self finishWithError:[NSError errorWithDomain:kQHTTPOperationErrorDomain code:kQHTTPOperationErrorBadContentType userInfo:nil]];
|
||||||
|
} else {
|
||||||
|
[self finishWithError:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
|
||||||
|
// See comment in header.
|
||||||
|
{
|
||||||
|
assert(self.isActualRunLoopThread);
|
||||||
|
assert(connection == self.connection);
|
||||||
|
#pragma unused(connection)
|
||||||
|
assert(error != nil);
|
||||||
|
|
||||||
|
[self finishWithError:error];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NSString * kQHTTPOperationErrorDomain = @"kQHTTPOperationErrorDomain";
|
||||||
30
QHTTPOperation/QReachabilityOperation.h
Normal file
30
QHTTPOperation/QReachabilityOperation.h
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#import "QRunLoopOperation.h"
|
||||||
|
#include <SystemConfiguration/SystemConfiguration.h>
|
||||||
|
|
||||||
|
@interface QReachabilityOperation : QRunLoopOperation {
|
||||||
|
NSString * _hostName;
|
||||||
|
NSUInteger _flagsTargetMask;
|
||||||
|
NSUInteger _flagsTargetValue;
|
||||||
|
NSUInteger _flags;
|
||||||
|
SCNetworkReachabilityRef _ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialises the operation to monitor the reachability of the specified
|
||||||
|
// host. The operation finishes when (flags & flagsTargetMask) == flagsTargetValue.
|
||||||
|
- (id)initWithHostName:(NSString *)hostName;
|
||||||
|
|
||||||
|
// Things that are configured by the init method and can't be changed.
|
||||||
|
@property (copy, readonly ) NSString * hostName;
|
||||||
|
|
||||||
|
// Things you can configure before queuing the operation.
|
||||||
|
|
||||||
|
// runLoopThread and runLoopModes inherited from QRunLoopOperation
|
||||||
|
@property (assign, readwrite) NSUInteger flagsTargetMask;
|
||||||
|
@property (assign, readwrite) NSUInteger flagsTargetValue;
|
||||||
|
|
||||||
|
// Things that change as part of the progress of the operation.
|
||||||
|
|
||||||
|
// error property inherited from QRunLoopOperation
|
||||||
|
@property (assign, readonly ) NSUInteger flags; // observable, changes on the actual run loop thread
|
||||||
|
|
||||||
|
@end
|
||||||
111
QHTTPOperation/QReachabilityOperation.m
Normal file
111
QHTTPOperation/QReachabilityOperation.m
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
#import "QReachabilityOperation.h"
|
||||||
|
|
||||||
|
@interface QReachabilityOperation ()
|
||||||
|
|
||||||
|
@property (assign, readwrite) NSUInteger flags;
|
||||||
|
|
||||||
|
static void ReachabilityCallback(
|
||||||
|
SCNetworkReachabilityRef target,
|
||||||
|
SCNetworkReachabilityFlags flags,
|
||||||
|
void * info
|
||||||
|
);
|
||||||
|
|
||||||
|
- (void)reachabilitySetFlags:(NSUInteger)newValue;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation QReachabilityOperation
|
||||||
|
|
||||||
|
- (id)initWithHostName:(NSString *)hostName {
|
||||||
|
assert(hostName != nil);
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil) {
|
||||||
|
self->_hostName = [hostName copy];
|
||||||
|
self->_flagsTargetMask = kSCNetworkReachabilityFlagsReachable | kSCNetworkReachabilityFlagsInterventionRequired;
|
||||||
|
self->_flagsTargetValue = kSCNetworkReachabilityFlagsReachable;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[self->_hostName release];
|
||||||
|
assert(self->_ref == NULL);
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize hostName = _hostName;
|
||||||
|
@synthesize flagsTargetMask = _flagsTargetMask;
|
||||||
|
@synthesize flagsTargetValue = _flagsTargetValue;
|
||||||
|
@synthesize flags = _flags;
|
||||||
|
|
||||||
|
// Called by QRunLoopOperation when the operation starts. This is our opportunity
|
||||||
|
// to install our run loop callbacks, which is exactly what we do. The only tricky
|
||||||
|
// thing is that we have to schedule the reachability ref to run in all of the
|
||||||
|
// run loop modes specified by our client.
|
||||||
|
- (void)operationDidStart {
|
||||||
|
Boolean success;
|
||||||
|
SCNetworkReachabilityContext context = { 0, self, NULL, NULL, NULL };
|
||||||
|
|
||||||
|
assert(self->_ref == NULL);
|
||||||
|
self->_ref = SCNetworkReachabilityCreateWithName(NULL, [self.hostName UTF8String]);
|
||||||
|
assert(self->_ref != NULL);
|
||||||
|
|
||||||
|
success = SCNetworkReachabilitySetCallback(self->_ref, ReachabilityCallback, &context);
|
||||||
|
assert(success);
|
||||||
|
|
||||||
|
for (NSString * mode in self.actualRunLoopModes) {
|
||||||
|
success = SCNetworkReachabilityScheduleWithRunLoop(self->_ref, CFRunLoopGetCurrent(), (CFStringRef) mode);
|
||||||
|
assert(success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ReachabilityCallback(
|
||||||
|
SCNetworkReachabilityRef target,
|
||||||
|
SCNetworkReachabilityFlags flags,
|
||||||
|
void * info
|
||||||
|
)
|
||||||
|
// Called by the system when the reachability flags change. We just forward
|
||||||
|
// the flags to our Objective-C code.
|
||||||
|
{
|
||||||
|
QReachabilityOperation * obj;
|
||||||
|
|
||||||
|
obj = (QReachabilityOperation *) info;
|
||||||
|
assert([obj isKindOfClass:[QReachabilityOperation class]]);
|
||||||
|
assert(target == obj->_ref);
|
||||||
|
#pragma unused(target)
|
||||||
|
|
||||||
|
[obj reachabilitySetFlags:flags];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when the reachability flags change. We just store the flags and then
|
||||||
|
// check to see if the flags meet our target criteria, in which case we stop the
|
||||||
|
// operation.
|
||||||
|
- (void)reachabilitySetFlags:(NSUInteger)newValue {
|
||||||
|
assert( [NSThread currentThread] == self.actualRunLoopThread );
|
||||||
|
|
||||||
|
self.flags = newValue;
|
||||||
|
if ( (self.flags & self.flagsTargetMask) == self.flagsTargetValue ) {
|
||||||
|
[self finishWithError:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by QRunLoopOperation when the operation finishes. We just clean up
|
||||||
|
// our reachability ref.
|
||||||
|
- (void)operationWillFinish {
|
||||||
|
Boolean success;
|
||||||
|
|
||||||
|
if (self->_ref != NULL) {
|
||||||
|
for (NSString * mode in self.actualRunLoopModes) {
|
||||||
|
success = SCNetworkReachabilityUnscheduleFromRunLoop(self->_ref, CFRunLoopGetCurrent(), (CFStringRef) mode);
|
||||||
|
assert(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
success = SCNetworkReachabilitySetCallback(self->_ref, NULL, NULL);
|
||||||
|
assert(success);
|
||||||
|
|
||||||
|
CFRelease(self->_ref);
|
||||||
|
self->_ref = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
119
QHTTPOperation/QRunLoopOperation.h
Normal file
119
QHTTPOperation/QRunLoopOperation.h
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
File: QRunLoopOperation.h
|
||||||
|
|
||||||
|
Contains: An abstract subclass of NSOperation for async run loop based operations.
|
||||||
|
|
||||||
|
Written by: DTS
|
||||||
|
|
||||||
|
Copyright: Copyright (c) 2010 Apple Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
||||||
|
("Apple") in consideration of your agreement to the following
|
||||||
|
terms, and your use, installation, modification or
|
||||||
|
redistribution of this Apple software constitutes acceptance of
|
||||||
|
these terms. If you do not agree with these terms, please do
|
||||||
|
not use, install, modify or redistribute this Apple software.
|
||||||
|
|
||||||
|
In consideration of your agreement to abide by the following
|
||||||
|
terms, and subject to these terms, Apple grants you a personal,
|
||||||
|
non-exclusive license, under Apple's copyrights in this
|
||||||
|
original Apple software (the "Apple Software"), to use,
|
||||||
|
reproduce, modify and redistribute the Apple Software, with or
|
||||||
|
without modifications, in source and/or binary forms; provided
|
||||||
|
that if you redistribute the Apple Software in its entirety and
|
||||||
|
without modifications, you must retain this notice and the
|
||||||
|
following text and disclaimers in all such redistributions of
|
||||||
|
the Apple Software. Neither the name, trademarks, service marks
|
||||||
|
or logos of Apple Inc. may be used to endorse or promote
|
||||||
|
products derived from the Apple Software without specific prior
|
||||||
|
written permission from Apple. Except as expressly stated in
|
||||||
|
this notice, no other rights or licenses, express or implied,
|
||||||
|
are granted by Apple herein, including but not limited to any
|
||||||
|
patent rights that may be infringed by your derivative works or
|
||||||
|
by other works in which the Apple Software may be incorporated.
|
||||||
|
|
||||||
|
The Apple Software is provided by Apple on an "AS IS" basis.
|
||||||
|
APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
||||||
|
WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING
|
||||||
|
THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||||
|
COMBINATION WITH YOUR PRODUCTS.
|
||||||
|
|
||||||
|
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
||||||
|
INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY
|
||||||
|
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
|
||||||
|
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY
|
||||||
|
OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
|
||||||
|
OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
enum QRunLoopOperationState {
|
||||||
|
kQRunLoopOperationStateInited,
|
||||||
|
kQRunLoopOperationStateExecuting,
|
||||||
|
kQRunLoopOperationStateFinished
|
||||||
|
};
|
||||||
|
typedef enum QRunLoopOperationState QRunLoopOperationState;
|
||||||
|
|
||||||
|
@interface QRunLoopOperation : NSOperation
|
||||||
|
{
|
||||||
|
QRunLoopOperationState _state;
|
||||||
|
NSThread * _runLoopThread;
|
||||||
|
NSSet * _runLoopModes;
|
||||||
|
NSError * _error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Things you can configure before queuing the operation.
|
||||||
|
|
||||||
|
// IMPORTANT: Do not change these after queuing the operation; it's very likely that
|
||||||
|
// bad things will happen if you do.
|
||||||
|
|
||||||
|
@property (retain, readwrite) NSThread * runLoopThread; // default is nil, implying main thread
|
||||||
|
@property (copy, readwrite) NSSet * runLoopModes; // default is nil, implying set containing NSDefaultRunLoopMode
|
||||||
|
|
||||||
|
// Things that are only meaningful after the operation is finished.
|
||||||
|
|
||||||
|
@property (copy, readonly ) NSError * error;
|
||||||
|
|
||||||
|
// Things you can only alter implicitly.
|
||||||
|
|
||||||
|
@property (assign, readonly ) QRunLoopOperationState state;
|
||||||
|
@property (retain, readonly ) NSThread * actualRunLoopThread; // main thread if runLoopThread is nil, runLoopThread otherwise
|
||||||
|
@property (assign, readonly ) BOOL isActualRunLoopThread; // YES if the current thread is the actual run loop thread
|
||||||
|
@property (copy, readonly ) NSSet * actualRunLoopModes; // set containing NSDefaultRunLoopMode if runLoopModes is nil or empty, runLoopModes otherwise
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface QRunLoopOperation (SubClassSupport)
|
||||||
|
|
||||||
|
// Override points
|
||||||
|
|
||||||
|
// A subclass will probably need to override -operationDidStart and -operationWillFinish
|
||||||
|
// to set up and tear down its run loop sources, respectively. These are always called
|
||||||
|
// on the actual run loop thread.
|
||||||
|
//
|
||||||
|
// Note that -operationWillFinish will be called even if the operation is cancelled.
|
||||||
|
//
|
||||||
|
// -operationWillFinish can check the error property to see whether the operation was
|
||||||
|
// successful. error will be NSCocoaErrorDomain/NSUserCancelledError on cancellation.
|
||||||
|
//
|
||||||
|
// -operationDidStart is allowed to call -finishWithError:.
|
||||||
|
|
||||||
|
- (void)operationDidStart;
|
||||||
|
- (void)operationWillFinish;
|
||||||
|
|
||||||
|
// Support methods
|
||||||
|
|
||||||
|
// A subclass should call finishWithError: when the operation is complete, passing nil
|
||||||
|
// for no error and an error otherwise. It must call this on the actual run loop thread.
|
||||||
|
//
|
||||||
|
// Note that this will call -operationWillFinish before returning.
|
||||||
|
|
||||||
|
- (void)finishWithError:(NSError *)error;
|
||||||
|
|
||||||
|
@end
|
||||||
359
QHTTPOperation/QRunLoopOperation.m
Normal file
359
QHTTPOperation/QRunLoopOperation.m
Normal file
|
|
@ -0,0 +1,359 @@
|
||||||
|
/*
|
||||||
|
File: QRunLoopOperation.m
|
||||||
|
|
||||||
|
Contains: An abstract subclass of NSOperation for async run loop based operations.
|
||||||
|
|
||||||
|
Written by: DTS
|
||||||
|
|
||||||
|
Copyright: Copyright (c) 2010 Apple Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
||||||
|
("Apple") in consideration of your agreement to the following
|
||||||
|
terms, and your use, installation, modification or
|
||||||
|
redistribution of this Apple software constitutes acceptance of
|
||||||
|
these terms. If you do not agree with these terms, please do
|
||||||
|
not use, install, modify or redistribute this Apple software.
|
||||||
|
|
||||||
|
In consideration of your agreement to abide by the following
|
||||||
|
terms, and subject to these terms, Apple grants you a personal,
|
||||||
|
non-exclusive license, under Apple's copyrights in this
|
||||||
|
original Apple software (the "Apple Software"), to use,
|
||||||
|
reproduce, modify and redistribute the Apple Software, with or
|
||||||
|
without modifications, in source and/or binary forms; provided
|
||||||
|
that if you redistribute the Apple Software in its entirety and
|
||||||
|
without modifications, you must retain this notice and the
|
||||||
|
following text and disclaimers in all such redistributions of
|
||||||
|
the Apple Software. Neither the name, trademarks, service marks
|
||||||
|
or logos of Apple Inc. may be used to endorse or promote
|
||||||
|
products derived from the Apple Software without specific prior
|
||||||
|
written permission from Apple. Except as expressly stated in
|
||||||
|
this notice, no other rights or licenses, express or implied,
|
||||||
|
are granted by Apple herein, including but not limited to any
|
||||||
|
patent rights that may be infringed by your derivative works or
|
||||||
|
by other works in which the Apple Software may be incorporated.
|
||||||
|
|
||||||
|
The Apple Software is provided by Apple on an "AS IS" basis.
|
||||||
|
APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
||||||
|
WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING
|
||||||
|
THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||||
|
COMBINATION WITH YOUR PRODUCTS.
|
||||||
|
|
||||||
|
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
||||||
|
INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY
|
||||||
|
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
|
||||||
|
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY
|
||||||
|
OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
|
||||||
|
OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "QRunLoopOperation.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Theory of Operation
|
||||||
|
-------------------
|
||||||
|
Some critical points:
|
||||||
|
|
||||||
|
1. By the time we're running on the run loop thread, we know that all further state
|
||||||
|
transitions happen on the run loop thread. That's because there are only three
|
||||||
|
states (inited, executing, and finished) and run loop thread code can only run
|
||||||
|
in the last two states and the transition from executing to finished is
|
||||||
|
always done on the run loop thread.
|
||||||
|
|
||||||
|
2. -start can only be called once. So run loop thread code doesn't have to worry
|
||||||
|
about racing with -start because, by the time the run loop thread code runs,
|
||||||
|
-start has already been called.
|
||||||
|
|
||||||
|
3. -cancel can be called multiple times from any thread. Run loop thread code
|
||||||
|
must take a lot of care with do the right thing with cancellation.
|
||||||
|
|
||||||
|
Some state transitions:
|
||||||
|
|
||||||
|
1. init -> dealloc
|
||||||
|
2. init -> cancel -> dealloc
|
||||||
|
XXX 3. init -> cancel -> start -> finish -> dealloc
|
||||||
|
4. init -> cancel -> start -> startOnRunLoopThreadThread -> finish dealloc
|
||||||
|
!!! 5. init -> start -> cancel -> startOnRunLoopThreadThread -> finish -> cancelOnRunLoopThreadThread -> dealloc
|
||||||
|
XXX 6. init -> start -> cancel -> cancelOnRunLoopThreadThread -> startOnRunLoopThreadThread -> finish -> dealloc
|
||||||
|
XXX 7. init -> start -> cancel -> startOnRunLoopThreadThread -> cancelOnRunLoopThreadThread -> finish -> dealloc
|
||||||
|
8. init -> start -> startOnRunLoopThreadThread -> finish -> dealloc
|
||||||
|
9. init -> start -> startOnRunLoopThreadThread -> cancel -> cancelOnRunLoopThreadThread -> finish -> dealloc
|
||||||
|
!!! 10. init -> start -> startOnRunLoopThreadThread -> cancel -> finish -> cancelOnRunLoopThreadThread -> dealloc
|
||||||
|
11. init -> start -> startOnRunLoopThreadThread -> finish -> cancel -> dealloc
|
||||||
|
|
||||||
|
Markup:
|
||||||
|
XXX means that the case doesn't happen.
|
||||||
|
!!! means that the case is interesting.
|
||||||
|
|
||||||
|
Described:
|
||||||
|
|
||||||
|
1. It's valid to allocate an operation and never run it.
|
||||||
|
2. It's also valid to allocate an operation, cancel it, and yet never run it.
|
||||||
|
3. While it's valid to cancel an operation before it starting it, this case doesn't
|
||||||
|
happen because -start always bounces to the run loop thread to maintain the invariant
|
||||||
|
that the executing to finished transition always happens on the run loop thread.
|
||||||
|
4. In this -startOnRunLoopThread detects the cancellation and finishes immediately.
|
||||||
|
5. Because the -cancel can happen on any thread, it's possible for the -cancel
|
||||||
|
to come in between the -start and the -startOnRunLoop thread. In this case
|
||||||
|
-startOnRunLoopThread notices isCancelled and finishes straightaway. And
|
||||||
|
-cancelOnRunLoopThread detects that the operation is finished and does nothing.
|
||||||
|
6. This case can never happen because -performSelecton:onThread:xxx
|
||||||
|
callbacks happen in order, -start is synchronised with -cancel, and -cancel
|
||||||
|
only schedules if -start has run.
|
||||||
|
7. This case can never happen because -startOnRunLoopThread will finish immediately
|
||||||
|
if it detects isCancelled (see case 5).
|
||||||
|
8. This is the standard run-to-completion case.
|
||||||
|
9. This is the standard cancellation case. -cancelOnRunLoopThread wins the race
|
||||||
|
with finish, and it detects that the operation is executing and actually cancels.
|
||||||
|
10. In this case the -cancelOnRunLoopThread loses the race with finish, but that's OK
|
||||||
|
because -cancelOnRunLoopThread already does nothing if the operation is already
|
||||||
|
finished.
|
||||||
|
11. Cancellating after finishing still sets isCancelled but has no impact
|
||||||
|
on the RunLoop thread code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@interface QRunLoopOperation ()
|
||||||
|
|
||||||
|
// read/write versions of public properties
|
||||||
|
|
||||||
|
@property (assign, readwrite) QRunLoopOperationState state;
|
||||||
|
@property (copy, readwrite) NSError * error;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation QRunLoopOperation
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil) {
|
||||||
|
assert(self->_state == kQRunLoopOperationStateInited);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
assert(self->_state != kQRunLoopOperationStateExecuting);
|
||||||
|
[self->_runLoopModes release];
|
||||||
|
[self->_runLoopThread release];
|
||||||
|
[self->_error release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark * Properties
|
||||||
|
|
||||||
|
@synthesize runLoopThread = _runLoopThread;
|
||||||
|
@synthesize runLoopModes = _runLoopModes;
|
||||||
|
|
||||||
|
- (NSThread *)actualRunLoopThread
|
||||||
|
// Returns the effective run loop thread, that is, the one set by the user
|
||||||
|
// or, if that's not set, the main thread.
|
||||||
|
{
|
||||||
|
NSThread * result;
|
||||||
|
|
||||||
|
result = self.runLoopThread;
|
||||||
|
if (result == nil) {
|
||||||
|
result = [NSThread mainThread];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isActualRunLoopThread
|
||||||
|
// Returns YES if the current thread is the actual run loop thread.
|
||||||
|
{
|
||||||
|
return [[NSThread currentThread] isEqual:self.actualRunLoopThread];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSSet *)actualRunLoopModes
|
||||||
|
{
|
||||||
|
NSSet * result;
|
||||||
|
|
||||||
|
result = self.runLoopModes;
|
||||||
|
if ( (result == nil) || ([result count] == 0) ) {
|
||||||
|
result = [NSSet setWithObject:NSDefaultRunLoopMode];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize error = _error;
|
||||||
|
|
||||||
|
#pragma mark * Core state transitions
|
||||||
|
|
||||||
|
- (QRunLoopOperationState)state
|
||||||
|
{
|
||||||
|
return self->_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setState:(QRunLoopOperationState)newState
|
||||||
|
// Change the state of the operation, sending the appropriate KVO notifications.
|
||||||
|
{
|
||||||
|
// any thread
|
||||||
|
|
||||||
|
@synchronized (self) {
|
||||||
|
QRunLoopOperationState oldState;
|
||||||
|
|
||||||
|
// The following check is really important. The state can only go forward, and there
|
||||||
|
// should be no redundant changes to the state (that is, newState must never be
|
||||||
|
// equal to self->_state).
|
||||||
|
|
||||||
|
assert(newState > self->_state);
|
||||||
|
|
||||||
|
// Transitions from executing to finished must be done on the run loop thread.
|
||||||
|
|
||||||
|
assert( (newState != kQRunLoopOperationStateFinished) || self.isActualRunLoopThread );
|
||||||
|
|
||||||
|
// inited + executing -> isExecuting
|
||||||
|
// inited + finished -> isFinished
|
||||||
|
// executing + finished -> isExecuting + isFinished
|
||||||
|
|
||||||
|
oldState = self->_state;
|
||||||
|
if ( (newState == kQRunLoopOperationStateExecuting) || (oldState == kQRunLoopOperationStateExecuting) ) {
|
||||||
|
[self willChangeValueForKey:@"isExecuting"];
|
||||||
|
}
|
||||||
|
if (newState == kQRunLoopOperationStateFinished) {
|
||||||
|
[self willChangeValueForKey:@"isFinished"];
|
||||||
|
}
|
||||||
|
self->_state = newState;
|
||||||
|
if (newState == kQRunLoopOperationStateFinished) {
|
||||||
|
[self didChangeValueForKey:@"isFinished"];
|
||||||
|
}
|
||||||
|
if ( (newState == kQRunLoopOperationStateExecuting) || (oldState == kQRunLoopOperationStateExecuting) ) {
|
||||||
|
[self didChangeValueForKey:@"isExecuting"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startOnRunLoopThread
|
||||||
|
// Starts the operation. The actual -start method is very simple,
|
||||||
|
// deferring all of the work to be done on the run loop thread by this
|
||||||
|
// method.
|
||||||
|
{
|
||||||
|
assert(self.isActualRunLoopThread);
|
||||||
|
assert(self.state == kQRunLoopOperationStateExecuting);
|
||||||
|
|
||||||
|
if ([self isCancelled]) {
|
||||||
|
|
||||||
|
// We were cancelled before we even got running. Flip the the finished
|
||||||
|
// state immediately.
|
||||||
|
|
||||||
|
[self finishWithError:[NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]];
|
||||||
|
} else {
|
||||||
|
[self operationDidStart];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)cancelOnRunLoopThread
|
||||||
|
// Cancels the operation.
|
||||||
|
{
|
||||||
|
assert(self.isActualRunLoopThread);
|
||||||
|
|
||||||
|
// We know that a) state was kQRunLoopOperationStateExecuting when we were
|
||||||
|
// scheduled (that's enforced by -cancel), and b) the state can't go
|
||||||
|
// backwards (that's enforced by -setState), so we know the state must
|
||||||
|
// either be kQRunLoopOperationStateExecuting or kQRunLoopOperationStateFinished.
|
||||||
|
// We also know that the transition from executing to finished always
|
||||||
|
// happens on the run loop thread. Thus, we don't need to lock here.
|
||||||
|
// We can look at state and, if we're executing, trigger a cancellation.
|
||||||
|
|
||||||
|
if (self.state == kQRunLoopOperationStateExecuting) {
|
||||||
|
[self finishWithError:[NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)finishWithError:(NSError *)error
|
||||||
|
{
|
||||||
|
assert(self.isActualRunLoopThread);
|
||||||
|
// error may be nil
|
||||||
|
|
||||||
|
if (self.error == nil) {
|
||||||
|
self.error = error;
|
||||||
|
}
|
||||||
|
[self operationWillFinish];
|
||||||
|
self.state = kQRunLoopOperationStateFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark * Subclass override points
|
||||||
|
|
||||||
|
- (void)operationDidStart
|
||||||
|
{
|
||||||
|
assert(self.isActualRunLoopThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)operationWillFinish
|
||||||
|
{
|
||||||
|
assert(self.isActualRunLoopThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark * Overrides
|
||||||
|
|
||||||
|
- (BOOL)isConcurrent
|
||||||
|
{
|
||||||
|
// any thread
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isExecuting
|
||||||
|
{
|
||||||
|
// any thread
|
||||||
|
return self.state == kQRunLoopOperationStateExecuting;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isFinished
|
||||||
|
{
|
||||||
|
// any thread
|
||||||
|
return self.state == kQRunLoopOperationStateFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)start
|
||||||
|
{
|
||||||
|
// any thread
|
||||||
|
|
||||||
|
assert(self.state == kQRunLoopOperationStateInited);
|
||||||
|
|
||||||
|
// We have to change the state here, otherwise isExecuting won't necessarily return
|
||||||
|
// true by the time we return from -start. Also, we don't test for cancellation
|
||||||
|
// here because that would a) result in us sending isFinished notifications on a
|
||||||
|
// thread that isn't our run loop thread, and b) confuse the core cancellation code,
|
||||||
|
// which expects to run on our run loop thread. Finally, we don't have to worry
|
||||||
|
// about races with other threads calling -start. Only one thread is allowed to
|
||||||
|
// start us at a time.
|
||||||
|
|
||||||
|
self.state = kQRunLoopOperationStateExecuting;
|
||||||
|
[self performSelector:@selector(startOnRunLoopThread) onThread:self.actualRunLoopThread withObject:nil waitUntilDone:NO modes:[self.actualRunLoopModes allObjects]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)cancel
|
||||||
|
{
|
||||||
|
BOOL runCancelOnRunLoopThread;
|
||||||
|
BOOL oldValue;
|
||||||
|
|
||||||
|
// any thread
|
||||||
|
|
||||||
|
// We need to synchronise here to avoid state changes to isCancelled and state
|
||||||
|
// while we're running.
|
||||||
|
|
||||||
|
@synchronized (self) {
|
||||||
|
oldValue = [self isCancelled];
|
||||||
|
|
||||||
|
// Call our super class so that isCancelled starts returning true immediately.
|
||||||
|
|
||||||
|
[super cancel];
|
||||||
|
|
||||||
|
// If we were the one to set isCancelled (that is, we won the race with regards
|
||||||
|
// other threads calling -cancel) and we're actually running (that is, we lost
|
||||||
|
// the race with other threads calling -start and the run loop thread finishing),
|
||||||
|
// we schedule to run on the run loop thread.
|
||||||
|
|
||||||
|
runCancelOnRunLoopThread = ! oldValue && self.state == kQRunLoopOperationStateExecuting;
|
||||||
|
}
|
||||||
|
if (runCancelOnRunLoopThread) {
|
||||||
|
[self performSelector:@selector(cancelOnRunLoopThread) onThread:self.actualRunLoopThread withObject:nil waitUntilDone:YES modes:[self.actualRunLoopModes allObjects]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
28
UIImage+AFNetworking.h
Normal file
28
UIImage+AFNetworking.h
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
// UIImage+AFNetworking.h
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
@interface UIImage (AFNetworking)
|
||||||
|
|
||||||
|
+ (UIImage *)imageByScalingAndCroppingImage:(UIImage *)image size:(CGSize)size;
|
||||||
|
+ (UIImage *)imageByRoundingCornersOfImage:(UIImage *)image corners:(UIRectCorner)corners cornerRadii:(CGSize)radii;
|
||||||
|
|
||||||
|
@end
|
||||||
81
UIImage+AFNetworking.m
Normal file
81
UIImage+AFNetworking.m
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
// UIImage+AFNetworking.m
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Gowalla (http://gowalla.com/)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#import "UIImage+AFNetworking.h"
|
||||||
|
|
||||||
|
@implementation UIImage (AFNetworking)
|
||||||
|
|
||||||
|
+ (UIImage *)imageByScalingAndCroppingImage:(UIImage *)image size:(CGSize)size {
|
||||||
|
if (image == nil) {
|
||||||
|
return nil;
|
||||||
|
} else if (CGSizeEqualToSize(image.size, size) || CGSizeEqualToSize(size, CGSizeZero)) {
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGSize scaledSize = size;
|
||||||
|
CGPoint thumbnailPoint = CGPointZero;
|
||||||
|
|
||||||
|
CGFloat widthFactor = size.width / image.size.width;
|
||||||
|
CGFloat heightFactor = size.height / image.size.height;
|
||||||
|
CGFloat scaleFactor = (widthFactor > heightFactor) ? widthFactor : heightFactor;
|
||||||
|
scaledSize.width = image.size.width * scaleFactor;
|
||||||
|
scaledSize.width = image.size.height * scaleFactor;
|
||||||
|
if (widthFactor > heightFactor) {
|
||||||
|
thumbnailPoint.y = (size.height - scaledSize.height) * 0.5;
|
||||||
|
} else if (widthFactor < heightFactor) {
|
||||||
|
thumbnailPoint.x = (size.width - scaledSize.width) * 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
|
||||||
|
[image drawInRect:CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledSize.width, scaledSize.height)];
|
||||||
|
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||||
|
UIGraphicsEndImageContext();
|
||||||
|
|
||||||
|
return newImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (UIImage *)imageByRoundingCornersOfImage:(UIImage *)image corners:(UIRectCorner)corners cornerRadii:(CGSize)radii {
|
||||||
|
if (image == nil) {
|
||||||
|
return nil;
|
||||||
|
} else if(UIGraphicsBeginImageContextWithOptions != NULL) {
|
||||||
|
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
|
||||||
|
} else {
|
||||||
|
UIGraphicsBeginImageContext(image.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextAddPath(context, [[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.0f, 0.0f, image.size.width, image.size.height) byRoundingCorners:corners cornerRadii:radii] CGPath]);
|
||||||
|
CGContextClosePath(context);
|
||||||
|
CGContextClip(context);
|
||||||
|
|
||||||
|
CGRect rect = CGRectMake(0.0f, 0.0f, image.size.width, image.size.height);
|
||||||
|
[image drawInRect:rect];
|
||||||
|
|
||||||
|
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||||
|
UIGraphicsEndImageContext();
|
||||||
|
|
||||||
|
return newImage;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
Loading…
Add table
Reference in a new issue