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:、読み込みバーを毎回更新するための単なる方法です。問題は、画像を1つずつダウンロードし始めたときに始まりますが、それらは解放されず、ループが終了するまでヒープに残ります。終了する前にループを停止すると、それらも解放されます。問題は、ループがそれらを実行するときですリリースされず、ダウンロードと保存後にヒープに残っています。instrument で確認できるのは、CFData (ストア)が毎回大きくなり、ループが終了するとリリースされることです。

4

1 に答える 1

0

私は、声明を推測します

_urlData = [NSData dataWithContentsOfURL:url] ;

「自動解放された」オブジェクトを返します。

これには、次の結果があります。

内側のループで自動解放プールを使用しないため、返されたすべてのデータ オブジェクトを、内側のループの外側のどこかで排出される自動解放プールに効果的に「保持」します。

この問題を軽減するには、単純にループ内に自動解放プールを配置して、返されたオブジェクトdataWithContentsOfURL:が解放され、内側のループの自動解放プールのスコープを離れるようにします。

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

自動解放プールを使用するとこの問題を回避できる可能性がありますが、正直なところ、現在の方法を見直して再実装する必要があります。たとえば、dispatch_sync() の使用方法は意味がありません。

NSURLConnectionの非同期の便利なメソッドを使用するか、デリゲート アプローチを使用すると、コードを大幅に改善することもできます。(非同期パターンの経験が豊富でない限り、非同期タスクのリストを非同期で起動するのはそれほど簡単ではないことを知っているにもかかわらず、私はこれを言っています。)

于 2013-11-04T18:23:05.420 に答える