0

我通常不喜欢问问题,但这次没有找到解决我问题的方法,所以我不得不问你如何解决我的问题。

我创建了一个对象OffLineModeBrain用于在应用程序正常运行时在后台下载大量图像,我编写代码,一切正常我只是内存有问题,我已经尝试了每个解决方案来一次次释放它但没有结果。基本上在我的 OffLineModeBrain中,我有一个方法可以做到这一点并加载一个进度条,这是代码:

-(void)downloadAndSaveByArray:(NSArray *)array{


    //PATH
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *paths = NSSearchPathForDirectoriesInDomains( NSCachesDirectory,
                                                         NSUserDomainMask, YES);
    NSString *cachesDirectory = [paths objectAtIndex:0];
    NSString *cachesImageFolderPath = [cachesDirectory stringByAppendingPathComponent:@"com.hackemist.SDWebImageCache.default"];

    dispatch_queue_t queueImages = dispatch_queue_create("Images", NULL);
    dispatch_queue_t queueDownload = dispatch_queue_create("Download", NULL);
    //dispatch_queue_t queueStore = dispatch_queue_create("Store", NULL);

    int total = array.count;
    __block int progess = 0;
    __weak OffLineModeBrain *wself = self;
    dispatch_sync(queueImages, ^{
    for ( NSString *image in array) {
        if (_stop) {
            //
            NSLog(@"stop");
            _stop = NO;
            _downloading = NO;
            break;

        }else{
            //CHECK IMAGE IN LOCAL
            BOOL success = [fileManager fileExistsAtPath:
                            [cachesImageFolderPath stringByAppendingPathComponent:
                             [NSString stringWithFormat:@"/%@", [[image MD5String] lowercaseString]]]];
            if (!success) {
                dispatch_sync(queueDownload, ^{
                    if (!_stop) {

                        //DOWNLOAD AND SAVE
                        NSError *error;
                        NSURL  *url =  [NSURL URLWithString:image];
                        _urlData = [NSData dataWithContentsOfURL:url] ;
                        NSLog(@"Download");

                        if (_urlData)
                        {
                            //dispatch_sync(queueStore, ^{

                                NSString  *filePath = [NSString stringWithFormat:@"%@/%@", cachesImageFolderPath, [image MD5String]];
                                [_urlData writeToFile:filePath atomically:NO];
                                NSLog(@"Stored");

                                //RETURN PROGRESS
                                progess = progess + 1;
                                [wself.delegate downloadImagesProgress:progess ofTotal:total];

                            //});


                        }else{
                            NSLog(@"Download Images erroe: %@", error);

                            //RETURN PROGRESS
                            progess = progess + 1;
                            [wself.delegate downloadImagesProgress:progess ofTotal:total];
                        }
                        //dsf
                    }else{
                        NSLog(@"stop");
                        progess = progess + 1;
                        if (progess == total) {
                            _stop = NO;

                        }
                        _downloading = NO;
                    }
                });


            }else{
                NSLog(@"Local");

                //RETURN PROGRESS
                progess = progess + 1;
                [wself.delegate downloadImagesProgress:progess ofTotal:total];
            }
        }

    }//FOR IMAGES ENDED
    });

}

downloadImagesProgress: ofTotal:只是每次更新加载栏的一种方法。当我开始一个接一个地下载图像时问题就开始了,然后它们没有释放并且仍然在堆中直到循环结束,如果在结束它们之前停止循环也是释放,问题是当循环运行它们时下载和存储后没有释放并且仍然在堆中,我在仪器中可以看到CFData(存储)每次都在增长,并且在循环结束时将被释放。

4

1 回答 1

0

我猜,声明

_urlData = [NSData dataWithContentsOfURL:url] ;

将返回一个“自动释放”对象。

这会产生以下后果:

由于您不在内部循环中使用自动释放池,因此您有效地将所有返回的数据对象“保存”在自动释放池中,该自动释放池在内部循环之外的某处被排出。

为了缓解这个问题,只需在循环中放置一个自动释放池,以便dataWithContentsOfURL:在离开内部循环的自动释放池范围的同时释放返回的对象:

for (...) {
    @autoreleasepool {
        ...
        NSData* data = [NSData dataWithContentsOfURL:url];
        ...
    }
}

虽然使用自动释放池可能有助于解决这个问题,但老实说,您还应该查看并重新实现您当前的方法。例如,您使用 dispatch_sync() 的方式没有意义。

如果您使用NSURLConnection's 的异步便捷方法,您还可以大大改进您的代码 - 甚至更好地使用委托方法。(我是这么说的,尽管我知道异步启动异步任务列表并不容易,除非您对异步模式有丰富的经验。)

于 2013-11-04T18:23:05.420 回答