使用AFNetworking按顺序下载图像



如何使用AFNetworking按顺序下载图像?我所说的"按顺序"也指按顺序执行success块。

最初我认为使用NSOperationQueue并将每个AFImageRequestOperation设置为下一个的依赖项就足够了。这样的:

- (void) downloadImages
{
    { // Reset
        [_downloadQueue cancelAllOperations];
        _downloadQueue = [[NSOperationQueue alloc] init];
        _images = [NSMutableArray array];
    }
    AFImageRequestOperation *previousOperation = nil;
    for (NSInteger i = 0; i < _imageURLs.count; i++) {
        NSURL *URL = [_imageURLs objectAtIndex:i];
        NSURLRequest *request = [NSURLRequest requestWithURL:URL];
        AFImageRequestOperation *operation = [AFImageRequestOperation 
                                              imageRequestOperationWithRequest:request 
                                              imageProcessingBlock:nil 
        success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
            [_images addObject:image];
            NSLog(@"%d", i);
        } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {}];
        if (previousOperation) {
            [operation addDependency:previousOperation];
        }
        previousOperation = operation;
        [_downloadQueue addOperation:operation];
    }
}

在下载图像时按顺序打印i。但是,当请求已经被缓存时,成功块的处理顺序是乱的。我怀疑这是NSOperation的限制,而不是AFNetworking。

我错过了什么吗?

作为一种解决方法,我将图像存储在字典中,并在每次请求成功时按顺序处理它们。这样的:

- (void) downloadImages
{
    { // Reset
        [_downloadQueue cancelAllOperations];
        _downloadQueue = [[NSOperationQueue alloc] init];
        _images = [NSMutableArray array];
        _imageDictionary = [NSMutableDictionary dictionary];
    }
    AFImageRequestOperation *previousOperation = nil;
    for (NSInteger i = 0; i < _imageURLs.count; i++) {
        NSURL *URL = [_imageURLs objectAtIndex:i];
        NSURLRequest *request = [NSURLRequest requestWithURL:URL];
        AFImageRequestOperation *operation = [AFImageRequestOperation 
                                              imageRequestOperationWithRequest:request 
                                              imageProcessingBlock:nil 
        success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
            [_imageDictionary setObject:image forKey:@(i)];
            [self processImages];
        } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {}];
        if (previousOperation) {
            [operation addDependency:previousOperation];
        }
        previousOperation = operation;
        [_downloadQueue addOperation:operation];
    }
}
- (void) processImages 
{
    for (NSInteger i = _images.count; i < _imageURLs.count; i++) {
        UIImage *image = [_imageDictionary objectForKey:@(i)];
        if (!image) break;
        [_images addObject:image];
        NSLog(@"%d", i);
    }
}

总是按顺序打印i

你的解决方案会很好,这里有另一种方法:

为了"完美"的用户体验,你应该并行地发布所有操作,并在图像出现时按顺序处理它们(如果没有必要,就不要等待)。(这里的错误处理方式不同)
你可以试试这个(未经测试,你可以更好地设计模型[不要只使用这样的数组]):

- (void) processImage:(UIImage*)image
{
    //do something with the image or just [_images addObject:image]
}
- (void) downloadImages
{
    { // Reset
        [_downloadQueue cancelAllOperations];
        _downloadQueue = [[NSOperationQueue alloc] init];
    }
    __block NSMutableArray* queue = [[NSMutableArray alloc] initWithCapacity:[_imageURLs count]];
    for (NSURL* url in _imageURLs) {
        __block NSLock* lock = [[NSLock alloc] init];
        __block NSMutableArray* container = [NSMutableArray new];
        [lock lock];
        [queue addObject:@[lock,container,url]];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        void(^compBlock)(NSURLRequest *request,
                         NSHTTPURLResponse *response,
                         UIImage *image) = ^(NSURLRequest *request,
                                             NSHTTPURLResponse *response,
                                             UIImage *image)
        {
            [container addObject:image];
            [lock unlock];
        };
        NSOperation *operation = [AFImageRequestOperation imageRequestOperationWithRequest:request
                                                                      imageProcessingBlock:nil
                                                                                   success:compBlock
                                                                                   failure:compBlock];
        [_downloadQueue addOperation:operation];
    }
    __block __weak id weakSelf = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (NSArray* arr in queue) {
            NSLock* lock = arr[0];
            [lock lock];
            NSMutableArray* container = arr[1];
            if ([container count]) {
                [weakSelf processImage:container[0]]; //might want to call this on main thread
            } else {
                //error on url = arr[2]
            }
            [lock unlock];
        }
    });    
}

最新更新