【问题标题】:Getting mp3 artwork crashes on iOS 8 but works on iOS 7获取 mp3 作品在 iOS 8 上崩溃,但在 iOS 7 上有效
【发布时间】: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.valueitem 和通过复制item.value 创建的字典。另外,能否请您发布回溯和崩溃日志本身?
  • @duci9y 感谢您的指导!请参阅上面的更新。似乎 item.value 是使用模拟器或 iPad 时的原始 UIImage 数据(而不是 NSDictionary)。很奇怪。你知道一种方法来确定 UIImage 与 NSDictionary 而不会使应用程序崩溃吗? (我现在正在研究这个。)
  • 对 MP3 使用AVMetadataID3MetadataKeyAttachedPicture,对 iTunes 使用AVMetadataiTunesMetadataKeyCoverArt,而不是通用键,看看是否能获得更可预测的结果。

标签: objective-c ipad ios-simulator mp3 avfoundation


【解决方案1】:

iOS 8 中返回的数据结构似乎发生了变化。AVMetadataItem 对象的value 不再是字典,而是实际的原始UIImage 数据。

NSFoundationVersionNumber 添加测试可以解决问题。可能有更清洁的解决方案。

- (void) viewDidAppear:(BOOL)animated
{
    self.titleText = @"Overkill";
    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]) {

                    // *** WE TEST THE IOS VERSION HERE ***

                    if (TARGET_OS_IPHONE && NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1) {
                        NSData *newImage = [item.value copyWithZone:nil];
                        albumArtWork = [UIImage imageWithData:newImage];
                    }
                    else {
                        NSDictionary *dict = [item.value copyWithZone:nil];
                        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];
                });
            }

        }];
    }

}

【讨论】:

  • 非常感谢斯坦!有时我想跳上去旧金山的飞机,扼杀一些苹果员工。为什么他们觉得有必要用这种我永远无法理解的废话来浪费我们的时间。
  • 我想当你开发了自己的操作系统并发布了几个版本之后你就可以理解它们了。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-27
相关资源
最近更新 更多