NSOpeation如何使用?
以下爲調用NSOperation,加到NSOperationQueue,便可運行。
PTOperationDownloader *downloader = [PTOperationDownloader
downloadWithURL:[NSURL URLWithString:URLString]
timeoutInterval:15
success:^(id responseData){
....
}
failure:^(NSError *error){
....
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:downloader];
@interface PTOperationDownloader : NSOperation
@property (nonatomic, readonly, retain) NSURL *URL;
@property (nonatomic, readonly, retain) NSMutableData* responseData;
@property(nonatomic, assign) BOOL finished2;
@property(nonatomic, assign) BOOL executing2;
+ (id)downloadWithURL:(NSURL *)URL
timeoutInterval:(NSTimeInterval)timeoutInterval
success:(void (^)(id responseData))success
failure:(void (^)(NSError *error))failure;
- (void)setCompletionBlockWithSuccess:(void (^)(id responseData))success
failure:(void (^)(NSError *error))failure;
當Queue addOperation後,便會調用start方法。
該方法中會啓動一個帶NSRunLoop的子線程networkThread。
- (void)start
{
[self.lock lock];
if ([self isCancelled])
{
[self willChangeValueForKey:@"isFinished"];
self.finished2 = YES;
[self didChangeValueForKey:@"isFinished"];
return;
}
[self willChangeValueForKey:@"isExecuting"];
[self performSelector:@selector(operationDidStart) onThread:[[self class] networkThread] withObject:nil waitUntilDone:NO];
self.executing2 = YES;
[self didChangeValueForKey:@"isExecuting"];
[self.lock unlock];
}
+ (void) __attribute__((noreturn)) networkEntry:(id)__unused object
{
do {
@autoreleasepool
{
[[NSRunLoop currentRunLoop] run];
NSLog(@"exit worker thread runloop");
}
} while (YES);
}
+ (NSThread *)networkThread
{
static NSThread *_networkThread = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkEntry:) object:nil];
[_networkThread start];
});
return _networkThread;
}
真正幹活開始,下載,使用NSURLConnection
- (void)operationDidStart
{
[self.lock lock];
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:self.URL
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:self.timeoutInterval];
[request setHTTPMethod: @"GET"];
self.connection =[[NSURLConnection alloc] initWithRequest:request
delegate:self
startImmediately:NO];
[self.connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[self.connection start];
[self.lock unlock];
}
NSURLConnection委託控制相關流程
#pragma mark - NSURLConnection Delegate
- (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)response
{
if (![response respondsToSelector:@selector(statusCode)] || [((NSHTTPURLResponse *)response) statusCode] < 400)
{
NSUInteger expectedSize = response.expectedContentLength > 0 ? (NSUInteger)response.expectedContentLength : 0;
self.responseData = [[NSMutableData alloc] initWithCapacity:expectedSize];
}
else
{
[aConnection cancel];
NSError *error = [[NSError alloc] initWithDomain:NSURLErrorDomain
code:[((NSHTTPURLResponse *)response) statusCode]
userInfo:nil];
self.error = error;
self.connection = nil;
self.responseData = nil;
self.completionBlock();
}
}
- (void)connection:(NSURLConnection *)aConnection didReceiveData:(NSData *)data
{
[self.responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection
{
NSLog(@"connectionDidFinishLoading in main thread?: %d", [NSThread isMainThread]);
self.connection = nil;
self.completionBlock();
[self operationDidFinish];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
self.connection = nil;
self.responseData = nil;
self.error = error;
self.completionBlock();
[self operationDidFinish];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
return nil;
}
重要的自定義委託,通過completionBlock, NSURLConnection委託出來的數據返回給外界調用者
- (void)setCompletionBlockWithSuccess:(void (^)(id responseData))success
failure:(void (^)(NSError *error))failure
{
[self.lock lock];
__weak typeof(self) weakSelf = self;
self.completionBlock = ^ {
if (weakSelf.error) {
if (failure) {
failure(weakSelf.error);
}
} else {
if (success) {
success(weakSelf.responseData);
}
}
};
[self.lock unlock];
}