下载通过数组循环的图像时的内存问题

时间:2015-01-18 21:14:02

标签: ios objective-c iphone memory-management automatic-ref-counting

我使用以下方法为阵列中的艺术家下载图像。我使用LastFm获取图片,然后将其存储在ESCache

self.imageDownloadingQueue = [[NSOperationQueue alloc] init];
self.imageDownloadingQueue.maxConcurrentOperationCount = 1;

self.artworkCache = [[ESCache alloc] initWithName:@"artworkCache" error:nil];

NSArray *artists = // get artists using relevant framework;

for (MPMediaItemCollection *collection in artists){

    [self.imageDownloadingQueue addOperationWithBlock:^{
        @autoreleasepool {

            MPMediaItem *item = [collection representativeItem];
            NSString *artistString = [item valueForProperty:MPMediaItemPropertyAlbumArtist];

            BOOL isCachedImage =   [self.artworkCache objectExistsForKey:artistString];;

            if (!isCachedImage){

                [[LastFm sharedInstance] getInfoForArtist:artistString successHandler:^(NSDictionary *result) {

                    if ([artistString isEqualToString:[[result objectForKey:@"_params"] objectForKey:@"artist"]]) {

                        NSURL *imageURL = [result objectForKey:@"image"];

                        if (imageURL){

                            NSData * data = [NSData dataWithContentsOfURL:imageURL];
                            UIImage *artistImage = [UIImage imageWithData:data];

                            [self.artworkCache setObject:artistImage forKey:artistString];

                            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                [downloadButton setTitle:artistString forState:UIControlStateNormal];
                                [downloadButton setBackgroundImage:artistImage forState:UIControlStateNormal];
                            }];
                            artistImage = nil;
                        }
                        else{
                            UIImage *newArtworkImage = // get placeholder image;

                            if (newArtworkImage != nil){

                                [self.artworkCache setObject:newArtworkImage forKey:artistString];

                                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                    [downloadButton setTitle:artistString forState:UIControlStateNormal];
                                    [downloadButton setBackgroundImage:newArtworkImage forState:UIControlStateNormal];
                                }];
                                newArtworkImage = nil;
                            }
                        }

                    }
                    else{


                    }
                } failureHandler:^(NSError *error) {

                }];
            }
        }
    }];
}

我看到我的内存使用量在Xcode中增加到超过200mb,然后我的应用程序崩溃并出现以下错误:

  

2015-01-18 20:56:36.479 Mezzo [1481:39314]收到内存警告。   Mezzo(1481,0x105254000)malloc: * mach_vm_map(size = 147456)失败   (错误代码= 3)   * 错误:无法分配区域   ***在malloc_error_break中设置断点以进行调试

它遍历前50位艺术家,获取他们的图像(我可以看到downloadButton更改)但随后崩溃。我不确定如何处理不断增加的内存使用问题。我将图片设置为nil后,我将其存储在autoreleasepool中。

如果循环遍历此数组,我还能如何减少内存使用量?任何帮助将非常感激。感谢。

1 个答案:

答案 0 :(得分:1)

  1. 任何需要一次将所有图像加载到内存中的模式都可能导致问题。将它们直接传输到持久存储。然后,根据UI的需要,将它们加载到图像视图(和缓存)中。

  2. 目前还不清楚用户界面是什么(即当前是否所有图片视图都可见,或者您是否正在填充滚动视图或类似内容)。仅将图像加载到需要在任何给定时间可见的内存中。如果您使用集合视图或表视图,这非常简单。如果您手动填充滚动视图,那么您必须完成一些工作以确定哪些是可见的,将其卸载为滚动屏幕等等。

  3. 确保缓存注册UIApplicationDidReceiveMemoryWarningNotification并在内存压力下清空缓存。缓存应该简单地用作优化UI速度的机制,但是在内存压力下,缓存应该清除自身,UI应该从持久存储中检索图像。因此,UI应该查看它是否在缓存中,如果是,请使用它。如果没有,请查看它是否在持久存储中,如果是,请使用它(在此过程中将其加载到缓存中)。并且只有在缓存或持久存储中找不到它才会从网络中检索它。

  4. 图片的分辨率是否高于用户界面要求的分辨率?例如,如果您的按钮为44 x 44 pt,并且屏幕比例为2,则将图像尺寸调整为88 x 88px。如果您resize them屏幕分辨率图像,则可以显着降低内存影响。

  5. 顺便说一下,一旦解决了这些内存问题,就可以重新评估maxConcurrentOperationCount 1。这会带来严重的性能损失。一般来说,我建议4或5.但是在你解决了记忆问题之前,不要解决这个问题。

    话虽如此,如果您正在进行异步下载,我希望您知道这会破坏maxConcurrentOperationCount 1的意图。如果要约束并发度,则必须将这些操作包装在异步NSOperation子类中(以及在异步下载完成之前不能完成操作的实现)。