我会提出一个解决方案,其中您有某种具有NSOperationQueue
它处理的通信管理器,使用单个入口点方法,您可以在其中为它提供您想要下载的内容所在的 URL,以及成功和失败块。通信管理器然后创建一个NSOperation
您创建NSURLRequest
和处理回调的位置。
一旦通信管理器将操作放入队列,它的start
方法就会被调用。在我的通信管理器实现中,我通过 an 跟踪(除了将操作放入队列中)每个启动的操作,NSMutableDictionary
以便您可以取消单个或所有操作(在提供的示例代码operationKey
中用于此目的。这里JSONOperation
返回(在成功的情况下)一个 NSString 到通信器,但它也可以是任何类型的数据,例如我使用相同的类来下载图像,所以我会传回数据对象本身。下面你可以找到我的 JSONOperation 类作为示例。我喜欢我可以将其他文件放在 Gist 上的想法。
我的NSOperation
长相是这样的
@interface JSONOperation : NSOperation <NSURLConnectionDataDelegate, OperationDelegate>
+ (instancetype)jsonOperationForProvider:(id)provider success:(OperationSuccessWithString)success failure:(OperationFailure)failure;
@end
#import "JSONOperation.h"
#import "ProviderDelegate.h"
@interface JSONOperation()
@property (nonatomic, assign) BOOL executing;
@property (nonatomic, assign) BOOL finished;
@property (nonatomic, assign) BOOL cancelled;
@property (nonatomic, strong) NSURL *url;
@property (nonatomic, weak) id <ProviderDelegate> delegate;
@property (nonatomic, strong) NSURLConnection *connection;
@property (nonatomic, strong) NSMutableData *receivedData;
@property (nonatomic, copy) OperationFailure failure;
@property (nonatomic, copy) OperationSuccessWithString success;
@end
@implementation JSONOperation
- (void)start
{
if ([self isCancelled])
{
[self willChangeValueForKey:@"isFinished"];
_finished = YES;
[self didChangeValueForKey:@"isFinished"];
return;
}
NSURLRequest *request = [NSURLRequest requestWithURL:self.url];
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[self.connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[self.connection start];
[self willChangeValueForKey:@"isExecuting"];
_executing = YES;
[self didChangeValueForKey:@"isExecuting"];
}
- (NSMutableData *)receivedData
{
if (nil == _receivedData) {
_receivedData = [NSMutableData data];
}
return _receivedData;
}
+ (instancetype)jsonOperationForProvider:(id <ProviderDelegate>)provider success:(OperationSuccessWithString)success failure:(OperationFailure)failure
{
NSAssert(nil != provider, @"provider parameter can't be nil");
JSONOperation *operation = [[[self class] alloc] init];
operation.delegate = provider;
operation.url = provider.contentURL;
operation.failure = failure;
operation.success = success;
return operation;
}
- (BOOL)isConcurrent {
return YES;
}
- (BOOL)isExecuting {
return _executing;
}
- (BOOL)isFinished {
return _finished;
}
- (BOOL)isCancelled {
return _cancelled;
}
#pragma mark - NSURLConnectionDataDelegate
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (_success) {
NSString *receivedText = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding];
_receivedData = nil;
self.success(self, receivedText);
}
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
_executing = NO;
_finished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[connection cancel];
_connection = nil;
_receivedData = nil;
_url = nil;
if (_failure) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.failure(self, error);
}];
}
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
_executing = NO;
_finished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
#pragma mark - OperationDelegate
- (NSString *)operationKey
{
return [self.url absoluteString];
}
- (id)provider
{
return _delegate;
}
- (void)cancelOperation
{
_failure = nil;
_success = nil;
[self.connection cancel];
_connection = nil;
_receivedData = nil;
_url = nil;
[self willChangeValueForKey:@"isCancelled"];
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
_executing = NO;
_finished = YES;
_cancelled = YES;
[self didChangeValueForKey:@"isCancelled"];
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
@end
编辑 - Gist 示例文件