EDIT: виновником был iOS 8, а не симулятор (который я не понимал, что уже работает iOS 8). Я переименовал заголовок, чтобы отразить это.Получение сбоев в работе с альбомами на iOS 8, но работает на iOS 7
Я с радостью воспользовался кодом this SO question, чтобы загрузить обложку альбома из mp3-файлов. Это было на моем iPhone 5 с iOS 7.1.
Но потом я проследил сбой в iOS-симуляторе этого кода. Дальнейшее исследование показало, что этот код также разбился на моем iPad. Он разбился на моем iPad после обновления его до iOS 8.
Похоже, что словарь, содержащий изображение, поврежден.
Я создал фиктивный проект iOS, который только загружает обложку альбома и получил тот же результат. Ниже приведен код этого диспетчера представлений.
- (void) viewDidAppear:(BOOL)animated
{
self.titleText = @"Overkill"; // Set song filename here
NSString *filePath = [[NSBundle mainBundle] pathForResource:self.titleText ofType:@"mp3"];
if (!filePath) {
return;
}
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
NSLog(@"Getting song metadata for %@", self.titleText);
AVAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
if (asset != nil) {
NSArray *keys = [NSArray arrayWithObjects:@"commonMetadata", nil];
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
NSArray *artworks = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata
withKey:AVMetadataCommonKeyArtwork
keySpace:AVMetadataKeySpaceCommon];
UIImage *albumArtWork;
for (AVMetadataItem *item in artworks) {
if ([item.keySpace isEqualToString:AVMetadataKeySpaceID3]) {
NSDictionary *dict = [item.value copyWithZone:nil];
// **********
// Crashes here with SIGABRT. dict is not a valid dictionary.
// **********
if ([dict objectForKey:@"data"]) {
albumArtWork = [UIImage imageWithData:[dict objectForKey:@"data"]];
}
}
else if ([item.keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
// This doesn't appear to get called for images set (ironically) in iTunes
albumArtWork = [UIImage imageWithData:[item.value copyWithZone:nil]];
}
}
if (albumArtWork != nil) {
dispatch_sync(dispatch_get_main_queue(), ^{
[self.albumArtImageView setImage:albumArtWork];
});
}
}];
}
}
Я отметил линию аварии. Он ожидает, что файл Overkill.mp3
будет в комплекте. Я тестировал с несколькими mp3 и m4a, экспортированными из iTunes и Amazon, поэтому я знаю, что сами файлы правильно закодированы.
Протестировано в Xcode 6.0 и 6.1.
Любые идеи, почему это будет работать на iPhone, но не на симуляторе или iPad?
EDIT/UPDATE:
Протоколирование item.value показывает различия.
На iPhone 5 (работа):
(lldb) po item.value
{
MIME = JPG;
data = <ffd8ffe0 .... several Kb of data ..... 2a17ffd9>;
identifier = "";
picturetype = Other;
}
На Simulator (сбои)
(lldb) po item.value
<ffd8ffe0 .... several Kb of data ..... 2a17ffd9>
Выходит, что на тренажере нет словаря, только сырая работа.
Изменение кода не ожидать словаря, но взять item.value
как UIImage работает!
for (AVMetadataItem *item in artworks) {
if ([item.keySpace isEqualToString:AVMetadataKeySpaceID3]) {
NSData *newImage = [item.value copyWithZone:nil];
albumArtWork = [UIImage imageWithData:newImage];
}
...
}
Ah ... Xcode 6.0. Должен сказать, я написал этот код, когда был еще новичком. С тех пор многое изменилось. Попробуйте logging 'item.value',' item' и словарь, созданные путем копирования 'item.value'. Кроме того, не могли бы вы разместить сообщение об ошибке и журнал сбоев? – duci9y
@ duci9y Спасибо за руководство посмотреть! См. Мое обновление выше. Кажется, что item.value - это сырые данные UIImage (а не NSDictionary) при использовании имитатора или iPad. Очень странно. Вы знаете способ определения UIImage vs NSDictionary без сбоев приложения? (Я сейчас изучаю это.) –
Используйте 'AVMetadataID3MetadataKeyAttachedPicture' для MP3 и' AVMetadataiTunesMetadataKeyCoverArt' для iTunes вместо общего ключа и посмотрите, получаете ли вы более предсказуемые результаты. – duci9y