iOS MAKImageGalleryView 使用 AFNetworking/AFImageDownloader 下载照片

iOS MAKImageGalleryView downloading photos using AFNetworking/AFImageDownloader

我正在尝试根据 MAKImageGalleryView, but I need download images from server, so I use AFImageDownloader (AFNetworking).

创建照片库

根据MAKImageGalleryView的文档,我必须实现这个方法:

MAKImageGalleryView.h

- (void)loadImageInGallery:(MAKImageGalleryView *)galleryView atIndex:(NSInteger)index callback:(void(^)(UIImage *))callback;

MAKImageGalleryView.m

#import "MAKImageGalleryView.h"

- (void)loadImageForRow:(NSInteger)row withBlockToCell:(MAKImageGalleryViewImageCell *)cell {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSUInteger key = random();
        cell.blockLoadingId = key;
        [self.imageGalleryDataSource loadImageInGallery:self atIndex:row callback:^(UIImage *image) {
            if (cell.blockLoadingId == key) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (cell.blockLoadingId == key) { //if still not reused
                        cell.image = image;
                    }
                });
            }
        }];
    });
}

所以我创建了类似的东西:

ViewController.m

- (void)loadImageInGallery:(MAKImageGalleryView *)galleryView atIndex:(NSInteger)index callback:(void(^)(UIImage *))callback{

    NSString * imageName = [NSString stringWithFormat:@"http://example.com/image%i.jpg", index];

    AFImageDownloader* download = [[AFImageDownloader alloc] init];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString: imageUrl] cachePolicy:NSURLRequestReturnCacheDataElseLoad
        timeoutInterval:60];
    [download downloadImageForURLRequest:request success:^(NSURLRequest * request, NSHTTPURLResponse * response, UIImage * image) {
        NSLog(@"Success download image");
        callback(image);
    } failure:^(NSURLRequest * request, NSHTTPURLResponse * response, NSError * error) {
        NSLog(@"Error download image");
    }];

结果: 时不时会看到一些照片,而另一些却看不到。

通过使用注释进行调试,似乎需要保留 AFImageDownloader 直到操作完成。如果不是,那么下载器很有可能会过早发布并自动终止下载。

您需要保留您的下载器。最直接的解决方案是使用强 属性 并将您的调用修改为:

- (void)loadImageInGallery:(MAKImageGalleryView *)galleryView atIndex:(NSInteger)index callback:(void(^)(UIImage *))callback{

    NSString * imageName = [NSString stringWithFormat:@"http://example.com/image%i.jpg", index];

    AFImageDownloader* download = [[AFImageDownloader alloc] init];
    self.currentDownloader = download;

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString: imageUrl] cachePolicy:NSURLRequestReturnCacheDataElseLoad
        timeoutInterval:60];
    ...

如果您有多个下载器,那么您需要将它们添加到数组中,但也需要将它们删除:

- (void)loadImageInGallery:(MAKImageGalleryView *)galleryView atIndex:(NSInteger)index callback:(void(^)(UIImage *))callback{

    NSString * imageName = [NSString stringWithFormat:@"http://example.com/image%i.jpg", index];

    AFImageDownloader* download = [[AFImageDownloader alloc] init];
    [self.currentDownloaders addObject: download];

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString: imageUrl] cachePolicy:NSURLRequestReturnCacheDataElseLoad
        timeoutInterval:60];
    [download downloadImageForURLRequest:request success:^(NSURLRequest * request, NSHTTPURLResponse * response, UIImage * image) {
        NSLog(@"Success download image");
        [self.currentDownloaders removeObject: download];
        callback(image);
    } failure:^(NSURLRequest * request, NSHTTPURLResponse * response, NSError * error) {
        NSLog(@"Error download image");
        [self.currentDownloaders removeObject: download];
    }];

或者就像我们在测试中所做的那样,您可以简单地让块保留下载:

只需在任何块内调用 NSLog(@"Success download image %@", download); 即可强制块保留 download。只要保留块,下载就会保留。至少在其中一个块被调用之前是这样。

这是最干净的过程,但由于该对象不是您创建的,您需要检查这些对象是否在某个时候被释放。如果它们没有正确完成,那么这段代码将产生一个保留周期并随之产生内存泄漏。

因此,在您使用最后一个程序之前,请检查以下内容:

子类 AFImageDownloader,覆盖 dealloc 并打印类似 NSLog(@"Did deallocate"); 的内容,并使用此子类代替您的 AFImageDownloader。如果您在某个时候看到日志 "Did deallocate",那么使用 "log trick" 是安全的。如果不是那么你不应该使用这个过程,因为它会产生内存泄漏!!!