2015-10-22 13 views
7

私はイメージ・ピッカー・ライブラリを使用して、フォト・ライブラリから多くのイメージを選択できます。それらはPHAssetsの配列として返されます。次に、PHAssetsをすべてUIImagesに変換し、アプリのストレージに書き込んでいます。PHAssetsとrequestImageForAssetを呼び出してメモリを大量に使用する

現在、私はすべての資産をループしており、requestImageForAssetを同期して呼び出しています。私の問題は、このループが実行されているときに、非常に高いメモリ使用量のスパイクがあるということです(イメージが30個あり、最大130MBになります)。私はこれを防ぐつもりです。ログに基づいて

for(PHAsset *asset in self.assets) { 
     NSLog(@"started requesting image %i", i); 
     [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:[self imageRequestOptions] resultHandler:^(UIImage *image, NSDictionary *info) { 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       assetCount++; 
       NSError *error = [info objectForKey:PHImageErrorKey]; 
       if (error) NSLog(@"Image request error: %@",error); 
       else { 
        NSString *imagePath = [appDelegate.docsPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%i.png",i]]; 
        NSData *imageData = UIImagePNGRepresentation(image); 
        if(imageData) { 
         [imageData writeToFile:imagePath atomically:YES]; 
         [self.imagesArray addObject:imagePath]; 
        } 
        else { 
         NSLog(@"Couldn't write image data to file."); 
        } 
        [self checkAddComplete]; 
        NSLog(@"finished requesting image %i", i); 
       } 
      }); 
     }]; 
    i++; 
} 

、私は完了ブロックのすべて、その後、すべての「開始要求画像がX」最初に呼び出されていることがわかり(「画像xを要求終了」:ここでは

は私のコードです)。私はこれが記憶上の問題に寄与していると思います。これらのリソースを解放して次の反復に移る前に、各反復の完了ブロックが呼び出されることを保証することは、おそらくメモリーの消費量が少なくなります。これどうやってするの?

答えて

4

メモリ管理にはautoreleasepoolを使用してください。

for(PHAsset *asset in self.assets) { 
    // This autorelease pool seems good (a1) 
    @autoreleasepool { 
     NSLog(@"started requesting image %i", i); 
     [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:[self imageRequestOptions] resultHandler:^(UIImage *image, NSDictionary *info) { 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       //you can add autorelease pool here as well (a2) 
       @autoreleasepool { 
        assetCount++; 
        NSError *error = [info objectForKey:PHImageErrorKey]; 
        if (error) NSLog(@"Image request error: %@",error); 
        else { 
         NSString *imagePath = [appDelegate.docsPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%i.png",i]]; 
         NSData *imageData = UIImagePNGRepresentation(image); 
         if(imageData) { 
          [imageData writeToFile:imagePath atomically:YES]; 
          [self.imagesArray addObject:imagePath]; 
         } 
         else { 
          NSLog(@"Couldn't write image data to file."); 
         } 
         [self checkAddComplete]; 
         NSLog(@"finished requesting image %i", i); 
        } 
       } //a2 ends here 
      }); 
     }]; 
     i++; 
    } // a1 ends here 
} 
+1

ありがとうございました。私はforループで@autoreleasepoolを試しましたが、そこにそれを置くと結果ハンドラがトリックでした! – Charles

+1

このトリックは私のためには機能しません。 :-s –

5

@Inderクマール・ラトーレのトリックは私のためには機能しません。 だからPHImageManager here

の詳細を読み取る試み私は

- requestImageDataForAsset:options:resultHandler:

- requestImageForAsset:targetSize:contentMode:options:resultHandler:

から切り替えた場合、私は同じ寸法{5376で画像を受信することを見出しました、2688}ですが、バイト単位のサイズはずっと小さくなっています。したがって、メモリの問題は解決されます。

願っています!

(注:[UIImage imageWithData:画像データ] UIImageへのNSDataを変換するためにこれを使用)

0

Iは完了ブロックが次の反復の前に終了されることを確実にする再帰方法でそれを解決しました。これにより、非常に少ないメモリで数千枚の写真を取得することができます。 は、ここでは何をするかです:

カメラロール内の選択した写真のインデックスの配列

  1. リクエストの最初のオブジェクトの配列内の指定されました。
  2. 完了ブロックで、配列内の最初のオブジェクトを削除し、同じメソッドを再度呼び出します。
  3. 繰り返し配列は、ここ

空になるまでコードです。

- (void)processPhotos 
{ 
    NSIndexPath *indexPath = [_selectedPhotosArray objectAtIndex:0]; 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    PHAsset *asset = [_allPhotos objectAtIndex:indexPath.row]; 
    [self.imageManager requestImageForAsset:asset 
           targetSize:PHImageManagerMaximumSize 
           contentMode:PHImageContentModeAspectFill 
            options:self.imageRequestOptions 
           resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { 
     NSError *error = [info objectForKey:PHImageErrorKey]; 
     if (_selectedPhotosArray.count > 0) { 
     [_selectedPhotosArray removeObjectAtIndex:0]; 
     } 
     if (error) { 
     NSLog(@"[CameraRoll] Image request error: %@",error); 
     } else { 
     if (result != nil) { 
      [self processImage:result]; 
     } 
     } 
     if (_selectedPhotosArray.count > 0) { 
     // Recurring loop 
     [self processPhotos]; 
     } 
    }]; 
    }); 
} 

このメソッドを初めて呼び出す前に、配列が空でないかどうかを確認してください。

+0

これで** @ autoreleasepool **を使うと、メモリ使用量をさらに減らすことができます。 –

関連する問題