【发布时间】:2014-04-12 17:22:04
【问题描述】:
我对@987654321@ 和NSOperationQueue 有几个不同的问题,我知道你们的回答会对我有所帮助;
我必须加载大量图像,并且我已经基于NSOperation、NSOperationQueue 和NSURLConnection(异步加载)创建了自己的加载器;
问题:
如果我为队列(
NSOperationQueue)设置maxConcurrentOperationCount(例如3),是否意味着即使队列有100个操作,同时也只有3个操作?当我为队列设置属性
maxConcurrentOperationCount时,有时“setCompletionBlock”不起作用并且计数(operationCount)只会增加;为什么?
我的加载器:
- (id)init
{
self = [super init];
if (self) {
_loadingFiles = [NSMutableDictionary new];
_downloadQueue = [NSOperationQueue new];
_downloadQueue.maxConcurrentOperationCount = 3;
_downloadQueue.name = @"LOADER QUEUE";
}
return self;
}
- (void)loadFile:(NSString *)fileServerUrl handler:(GetFileDataHandler)handler {
if (fileServerUrl.length == 0) {
return;
}
if ([_loadingFiles objectForKey:fileServerUrl] == nil) {
[_loadingFiles setObject:fileServerUrl forKey:fileServerUrl];
__weak NSMutableDictionary *_loadingFiles_ = _loadingFiles;
MyLoadOperation *operation = [MyLoadOperation new];
[operation fileServerUrl:fileServerUrl handler:^(NSData *fileData) {
[_loadingFiles_ removeObjectForKey:fileServerUrl];
if (fileData != nil) {
handler(fileData);
}
}];
[operation setQueuePriority:NSOperationQueuePriorityLow];
[_downloadQueue addOperation:operation];
__weak NSOperationQueue *_downloadQueue_ = _downloadQueue;
[operation setCompletionBlock:^{
NSLog(@"completion block :%i", _downloadQueue_.operationCount);
}];
}
}
我的操作:
@interface MyLoadOperation()
@property (nonatomic, assign, getter=isOperationStarted) BOOL operationStarted;
@property(nonatomic, strong)NSString *fileServerUrl;
@property(nonatomic, copy)void (^OnFinishLoading)(NSData *);
@end
@implementation MyLoadOperation
- (id)init
{
self = [super init];
if (self) {
_executing = NO;
_finished = NO;
}
return self;
}
- (void)fileServerUrl:(NSString *)fileServerUrl
handler:(void(^)(NSData *))handler {
@autoreleasepool {
self.fileServerUrl = fileServerUrl;
[self setOnFinishLoading:^(NSData *loadData) {
handler(loadData);
}];
[self setOnFailedLoading:^{
handler(nil);
}];
self.url = [[NSURL alloc] initWithString:self.fileServerUrl];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:self.url
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:25];
[request setValue:@"" forHTTPHeaderField:@"Accept-Encoding"];
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[self.connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[self.connection start];
_data = [[NSMutableData alloc] init];
}
}
- (void)main {
@autoreleasepool {
[self stop];
}
}
- (void)start {
[self setOperationStarted:YES];
[self willChangeValueForKey:@"isFinished"];
_finished = NO;
[self didChangeValueForKey:@"isFinished"];
if ([self isCancelled])
{
[self willChangeValueForKey:@"isFinished"];
_finished = YES;
_executing = NO;
[self didChangeValueForKey:@"isFinished"];
}
else
{
[self willChangeValueForKey:@"isExecuting"];
_finished = NO;
_executing = YES;
[self didChangeValueForKey:@"isExecuting"];
}
}
- (BOOL)isConcurrent {
return YES;
}
- (BOOL)isExecuting {
return _executing;
}
- (BOOL)isFinished {
return _finished;
}
- (void)cancel {
[self.connection cancel];
if ([self isExecuting])
{
[self stop];
}
[super cancel];
}
#pragma mark -NSURLConnectionDelegate
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[_data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if ([self OnFinishLoading]) {
[self OnFinishLoading](_data);
}
if (![self isCancelled]) {
[self stop];
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
;
if (![self isCancelled]) {
[self stop];
}
}
- (void)stop {
@try {
__weak MyLoadOperation *self_ = self;
dispatch_async(dispatch_get_main_queue(), ^{
[self_ completeOperation];
});
}
@catch (NSException *exception) {
NSLog(@"Exception! %@", exception);
[self completeOperation];
}
}
- (void)completeOperation {
if (![self isOperationStarted]) return;
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
_executing = NO;
_finished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
【问题讨论】:
-
明确地说,您是说当使用 3 个
maxConcurrentOperationCount时,您会看到所有 100 个操作都运行并完成(不仅仅是前三个),但看不到operationCount一点都不改变?operationCount方法并不完全可靠(请参阅该方法的文档),但您应该会看到返回值的一些变化。你能更详细地描述一下这种行为吗? -
感谢您的回答;是的,你是对的,我必须更好地描述这种行为;看,如果我删除了
maxConcurrentOperationCount,那么上面显示的代码一切正常;很好 - 我的意思是setCompletionBlock每次调用和operationCount减少;如果我使用maxConcurrentOperationCount(数字无关紧要)setCompletionBlock调用,但当我滚动tableview(显示加载图像的位置)时,它通常会停止工作;换句话说,我只更改了一行代码就改变了行为;
标签: ios objective-c nsurlconnection nsoperation nsoperationqueue