【发布时间】:2014-11-04 21:21:09
【问题描述】:
编辑:罪魁祸首是 iOS 8,而不是模拟器(我没有意识到它已经在运行 iOS 8)我重命名了标题以反映这一点。
我很高兴使用this SO question 中的代码从 mp3 文件加载专辑插图。这是在我的带有 iOS 7.1 的 iPhone 5 上。
但后来我在 iOS 模拟器中追踪到此代码的崩溃。进一步调查显示,这段代码在我的 iPad 上也崩溃了。升级到 iOS 8 后,它在我的 iPad 上崩溃了。
包含该图像的字典似乎已损坏。
我创建了一个虚拟 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 在捆绑包中。我测试了从 iTunes 和 Amazon 导出的多个 mp3 和 m4a,所以我知道文件本身是正确编码的。
在 Xcode 6.0 和 6.1 中测试。
任何想法为什么它可以在 iPhone 上运行,但不能在模拟器或 iPad 上运行?
编辑/更新:
记录 item.value 揭示差异。
在 iPhone 5 上(有效):
(lldb) po item.value
{
MIME = JPG;
data = <ffd8ffe0 .... several Kb of data ..... 2a17ffd9>;
identifier = "";
picturetype = Other;
}
在模拟器上(崩溃)
(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];
}
...
}
【问题讨论】:
-
啊……Xcode 6.0。必须告诉你,我还是初学者的时候就写了那个代码。从那以后很多事情改变了。尝试记录
item.value、item和通过复制item.value创建的字典。另外,能否请您发布回溯和崩溃日志本身? -
@duci9y 感谢您的指导!请参阅上面的更新。似乎 item.value 是使用模拟器或 iPad 时的原始 UIImage 数据(而不是 NSDictionary)。很奇怪。你知道一种方法来确定 UIImage 与 NSDictionary 而不会使应用程序崩溃吗? (我现在正在研究这个。)
-
对 MP3 使用
AVMetadataID3MetadataKeyAttachedPicture,对 iTunes 使用AVMetadataiTunesMetadataKeyCoverArt,而不是通用键,看看是否能获得更可预测的结果。
标签: objective-c ipad ios-simulator mp3 avfoundation