MPMediaItemArtwork imageWithSize: утечка памяти
Когда один звонит imageWithSize:
на любом MPMediaItemArtwork
объект, даже после всех ссылок на связанный MPMediaItem
а также UIImage
были отброшены, память все еще держится так, как будто на нее захватывает магическая ссылка.
Я создал целый отдельный проект для проверки этой конкретной утечки, и я очень обеспокоен тем, что это проблема с внутренним API, и что я ничего не могу с этим поделать.
Теперь давайте разберемся со старым добрым кодом. Один контроллер представления и 3 простых шага воспроизведут эту проблему. Мой код ниже делает это:
- Создает массив для изображений и получает массив
MPMediaItemCollection
объекты (с каждой коллекцией, содержащей только одну песню, для тестирования в худшем случае) - Для каждого представителя
MPMediaItem
в каждомMPMediaItemCollection
, изображение обложки альбома генерируется сCGSize
500х500. NSTimer
срабатывает через 3 секунды, что просто устанавливает все массивы, связанные с изображениями, наnil
ViewController.m:
#import <MediaPlayer/MediaPlayer.h>
#import "ViewController.h"
@interface ViewController ()
@property NSMutableArray *representativeImageArray;
@property NSMutableArray *collectionArray;
@end
@implementation ViewController
- (void)letItGo {
self.representativeImageArray = nil;
self.collectionArray = nil;
NSLog(@"Let go.");
}
- (void)viewDidLoad {
[super viewDidLoad];
self.representativeImageArray = [[NSMutableArray alloc]init];
self.collectionArray = [NSMutableArray arrayWithArray:[MPMediaQuery songsQuery].collections];
for(int i = 0; i < self.collectionArray.count; i++){
MPMediaItemCollection *collection = [self.collectionArray objectAtIndex:i];
for(int i1 = 0; i1 < collection.count; i1++){
MPMediaItem *representativeItem = [collection representativeItem];
UIImage *image = [representativeItem.artwork imageWithSize:CGSizeMake(500, 500)];
if(image){
[self.representativeImageArray addObject:image];
}
}
}
[NSTimer scheduledTimerWithTimeInterval:3.0
target:self
selector:@selector(letItGo)
userInfo:nil
repeats:NO];
NSLog(@"Got %ld items for collectionArray (%ld images).", self.collectionArray.count, self.representativeImageArray.count);
}
@end
Для 1210 изображений, сгенерированных из 1214 элементов (размером 500x500), ниже приведен график использования памяти:
По сравнению с графиком использования памяти, если не вызов imageWithSize:
совсем:
Теперь я видел людей, которые ранее предлагали использовать MPMediaItemArtwork
"s CGSize
от его bounds
имущество. Итак, давайте сделаем это вместо этого.
Давай меняться
UIImage *image = [representativeItem.artwork imageWithSize:CGSizeMake(500, 500)];
в
UIImage *image = [representativeItem.artwork imageWithSize:representativeItem.artwork.bounds.size];
Теперь, после запуска того же кода, что и в ViewController.m, хотя с одним этим изменением мы получаем это для использования памяти:
Да, массивы, связанные с изображениями, были отброшены, как в предыдущих двух запусках. Несмотря на то, что память все равно колеблется около 70 МБ, и, похоже, нет способа вернуться к ~10 МБ без полного перезапуска приложения.
Это интересная проблема, с которой я боролся весь день. Лично я более привык управлять памятью, исходящей из C-фона, и зная, что все утечки памяти в основном будут моей ошибкой. Извините, если что-то здесь полностью пролетело над моей головой.
Любая помощь будет принята с благодарностью, спасибо за чтение!