ARC не освобождает исходный актив после CGCreateWithImageInRect?

Краткий обзор высокого уровня: я хотел бы заменить изображения группы ALAsset с довольно низким разрешением [group posterImage] более качественной версией, чтобы они могли отображаться на экране в большем размере. Обычно я загружал бы их по мере необходимости интерфейсом, но [ALAssetsGroup enumerateAssetsAtIndexes] очень медленный. (Я МОГУ БЫТЬ предварительно загружен шире, чем видимый на x, и все еще могу это сделать, но это выглядело больше хлопот, чем стоило, и все еще страдает от медленного ответа, особенно в iOS5)

Я решил, что смогу запросить первый актив в каждой группе и затем масштабировать его, сохраняя результат. Однако, даже учитывая больший размер изображений, я удивляюсь тому, что происходит выделение памяти. Используя VM Tracker, я вижу БОЛЬШОЕ количество выделений CGImage, а также эскизы "сопоставленного файла", которые я создаю. Я использую ARC, поэтому я ожидал, что оригинальные большие изображения будут выпадать, но результаты моего VM Tracker этого не раскрывают.

Если я использую стандартную реализацию posterImage, то мои Resident Mem ~= 30 МБ, Dirty Mem ~= 80 МБ и виртуальные топы ~240 МБ (сами по себе большие). "Live" < 10 МБ на профилировщик распределения.

Если я вместо этого использую следующий код, я аварийно загружаю ~80-е изображение из 150. В этот момент мои Resident Mem > 480mb, Dirty Mem > 420mb и Virtual были колоссальными 750mb. Очевидно, что это несостоятельно.

Вот код, который я использую внутри NSOperationQueue, чтобы получить первое изображение каждой группы, которое будет использоваться в качестве изображения постера высокого разрешения.

NSIndexSet* i = [NSIndexSet indexSetWithIndex:0];
ALAssetsGroupEnumerationResultsBlock assetsEnumerationBlock = ^(ALAsset *result, NSUInteger i, BOOL *stop) {

  if (result) {
     // pull the full resolution image and then scale it to fit our desired area
     ALAssetRepresentation *assetRepresentation = [result defaultRepresentation];
     CGImageRef ref = [assetRepresentation fullScreenImage];
     CGFloat imgWidth = CGImageGetWidth(ref);
     CGFloat imgHeight = CGImageGetHeight(ref);
     CGFloat minDimension = MIN(imgWidth,imgHeight);

     // grab a square subset of the image, centered, to use
     CGRect subRect = CGRectMake(0, 0, minDimension, minDimension);
     subRect.origin = CGPointMake(imgWidth / 2 - minDimension / 2, imgHeight / 2 - minDimension / 2);
     CGImageRef squareRef = CGImageCreateWithImageInRect(ref,subRect);
     // now scale it down to fit
     CGFloat heightScale = dimension / minDimension;
     UIImage* coverImage = [UIImage imageWithCGImage:squareRef scale:1/heightScale orientation:UIImageOrientationUp];

     if (coverImage) {
        [mainViewController performSelectorOnMainThread:@selector(imageDidLoad:) 
                                             withObject:[NSArray arrayWithObjects:coverImage, [NSNumber numberWithInt:photoIndex], nil] 
                                          waitUntilDone:NO];
     }      
     CGImageRelease(squareRef);
     // DO NOT RELEASE 'ref' it will be 'zombied' as it is already handled by the system
     //CGImageRelease(ref);

     *stop = YES;
   }
   else {
      // default image grab....
   }
};
[group enumerateAssetsAtIndexes:i options:NSEnumerationConcurrent usingBlock:assetsEnumerationBlock];

Я делаю что-то не так с вышесказанным или я просто не умный, загружая все изображения? Чем больше я думаю об этом, тем больше я думаю, что загрузка окна видимых изображений плюс буфер вокруг него - это путь, но я хотел бы узнать больше о том, что я мог сделать неправильно с приведенным выше кодом. Спасибо!

1 ответ

Я сделал то же самое, что и вы, но благодаря этому ответу: извлекая последнее изображение, снятое на камеру iPhone, мне удалось сделать его намного быстрее и не тратить столько памяти.

Это, конечно, делает изображения намного меньше, поскольку вы не получаете fullScreenImage, а просто его миниатюру.

Мой окончательный код:

   ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

// Enumerate just the photos and videos group by using ALAssetsGroupSavedPhotos.
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {

    // Within the group enumeration block, filter to enumerate just photos.
    [group setAssetsFilter:[ALAssetsFilter allPhotos]];
    int nrOfPhotos = 200;
    [group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, nrOfPhotos)]
                            options:0
                         usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) {

                             // The end of the enumeration is signaled by asset == nil.
                             if (alAsset) {
                                 NSLog(@"Index: %i", index);

                                 CGImageRef imageRef = [alAsset thumbnail];
                                 UIImage *latestPhoto = [UIImage imageWithCGImage:imageRef scale:1.f orientation:UIImageOrientationUp];

                                 //Do something with images

                         }
                         }];
}
                     failureBlock: ^(NSError *error) {
                         // Typically you should handle an error more gracefully than this.
                         NSLog(@"No groups");
                     }];
Другие вопросы по тегам