2

我已经进入 iOS 编程几个星期了,还有很多东西要学。我有一种包含 MPMediaItems 的 NSMutableArray 工作,但是对于 1200 个项目,它慢了大约 10 秒,我正在寻找一种更快的方法。

我的最终目标是拥有一个 MPMediaItemCollection 项目数组,每个项目代表一个专辑。我无法从 MPMediaQuery(据我所知)中获取此信息,因为我需要从播放列表中获取歌曲。因此,我正在对从特定播放列表(“过去 4 个月”)中获得的歌曲进行排序,然后构建我自己的收藏集。正如我所说,下面的方法有效,但速度很慢。即使我只按 MPMediaItemPropertyAlbumTitle 排序,它仍然需要大约 4 秒(iPhone 4S)。

编辑:我应该提到我尝试了排序描述符,但我无法获得工作的关键。例如

NSSortDescriptor *titleDescriptor = [[NSSortDescriptor alloc] initWithKey:@"MPMediaItemPropertyAlbumTitle" ascending:YES];

这会返回一个错误

[<MPConcreteMediaItem 0x155e50> valueForUndefinedKey:]: this class is not key value coding-compliant for the key MPMediaItemPropertyAlbumTitle.

编码

MPMediaQuery *query = [MPMediaQuery playlistsQuery];
NSArray *playlists = [query collections];
NSMutableArray *songArray = [[NSMutableArray alloc] init];

for (MPMediaItemCollection *playlist in playlists) {
    NSString *playlistName = [playlist valueForProperty: MPMediaPlaylistPropertyName];
    NSLog (@"%@", playlistName);
    if ([playlistName isEqualToString:@"Last 4 months"]) {

        /* replaced this code with a mutable copy
        NSArray *songs = [playlist items];
        for (MPMediaItem *song in songs) {
            [songArray addObject:song]; 
        }
        */
        // the following replaces the above for-loop
        songArray = [[playlist items] mutableCopy ];

        [songArray sortUsingComparator:^NSComparisonResult(id a, id b) {
            NSString *first1 = [(MPMediaItem*)a valueForProperty:MPMediaItemPropertyAlbumTitle];
            NSString *second1 = [(MPMediaItem*)b valueForProperty:MPMediaItemPropertyAlbumTitle];

            NSString *first2 = [(MPMediaItem*)a valueForProperty:MPMediaItemPropertyAlbumPersistentID];
            NSString *second2 = [(MPMediaItem*)b valueForProperty:MPMediaItemPropertyAlbumPersistentID];

            NSString *first3 = [(MPMediaItem*)a valueForProperty:MPMediaItemPropertyAlbumTrackNumber];
            NSString *second3 = [(MPMediaItem*)b valueForProperty:MPMediaItemPropertyAlbumTrackNumber];

            NSString *first = [NSString stringWithFormat:@"%@%@%03d",first1,first2, [first3 intValue]];
            NSString *second = [NSString stringWithFormat:@"%@%@%03d",second1,second2, [second3 intValue]];

            return [first compare:second]; 
        }];
    }
}
4

3 回答 3

3

我知道这是一个旧线程,但我认为澄清为什么 OP 排序代码不起作用以便任何遇到此代码的人都不会推迟使用 NSSortDescriptors 很重要。

编码:

[[NSSortDescriptor alloc] initWithKey:@"MPMediaItemPropertyAlbumTitle" ascending:YES];

应该:

[[NSSortDescriptor alloc] initWithKey:MPMediaItemPropertyAlbumTitle ascending:YES];

因为 MPMediaItemPropertyAlbumTitle 包含密钥的名称。

我已经多次使用此代码。

于 2014-02-09T03:54:39.703 回答
2

在@cdelacroix 的建议下,我重新实现了比较块以级联三个排序键,如果高阶键相同,则只检查低阶键。这导致排序的执行时间减少了 50% 以上。尽管如此,它并没有我想要的那么快,所以如果有人有更好的答案,请发布它。

这是旧时代与新时代的对比(1221 项):

4S执行时间=10.8,执行时间=4.7

3GS 执行时间 = 21.6,执行时间 = 9.3

有趣的是,从 for 循环切换到数组副本的 mutableCopy 似乎并没有改善情况。如果有的话,mutableCopy 可能慢了十分之一秒(有人对 mutableCopy 进行过任何基准测试吗?)。但我留下了改变,因为它看起来更干净。

最后,注意检查专辑标题 == nil。请注意, compare 认为任何具有 nil 值的东西总是 NSOrderedSame 与其他任何东西一样。列表中的一张专辑没有设置标题,这在没有此检查的情况下搞砸了排序顺序。

MPMediaQuery *query = [MPMediaQuery playlistsQuery];
NSArray *playlists = [query collections];
NSMutableArray *songArray = [[NSMutableArray alloc] init];

for (MPMediaItemCollection *playlist in playlists) {
    NSString *playlistName = [playlist valueForProperty: MPMediaPlaylistPropertyName];
    NSLog (@"%@", playlistName);
    if ([playlistName isEqualToString:@"Last 4 months"]) {

        songArray = [[playlist items] mutableCopy ];

        [songArray sortUsingComparator:^NSComparisonResult(id a, id b) {
            NSComparisonResult compareResult;

            NSString *first1 = [(MPMediaItem*)a valueForProperty:MPMediaItemPropertyAlbumTitle];
            if(first1 == nil) first1 = @" "; // critical because compare will match nil to anything and result in NSOrderedSame
            NSString *second1 = [(MPMediaItem*)b valueForProperty:MPMediaItemPropertyAlbumTitle];
            if(second1 == nil) second1 = @" ";  // critical because compare will match nil to anything and result in NSOrderedSame
            compareResult = [first1 compare:second1];

            if (compareResult == NSOrderedSame) {
                NSString *first2 = [(MPMediaItem*)a valueForProperty:MPMediaItemPropertyAlbumPersistentID];
                NSString *second2 = [(MPMediaItem*)b valueForProperty:MPMediaItemPropertyAlbumPersistentID];
                compareResult = [first2 compare:second2];
                if(compareResult == NSOrderedSame) {
                    NSString *first3 = [(MPMediaItem*)a valueForProperty:MPMediaItemPropertyAlbumTrackNumber];
                    NSString *second3 = [(MPMediaItem*)b valueForProperty:MPMediaItemPropertyAlbumTrackNumber];
                    compareResult = [first3 compare:second3];
                }
            }
            return compareResult;
        }];
    }
}
于 2012-06-19T04:20:32.427 回答
0

您需要了解排序描述符

然后你的排序将尽可能简单,return [songs sortedArrayUsingDescriptors:sortDescriptors];也应该更快。

编辑:根据 OP, MPMediaItem 类不符合 KVC 标准,因此我将放弃答案。

于 2012-06-18T20:22:43.083 回答