2

私はiOSプログラミングを始めて数週間で、学ぶことがたくさんあります。MPMediaItemsを含むNSMutableArrayのようなものが機能していますが、1200のアイテムのようなものでは、約10秒遅く、より高速なアプローチを探しています。

私の最終的な目標は、それぞれがアルバムを表すMPMediaItemCollectionアイテムの配列を作成することです。プレイリストから曲を取得する必要があるため、MPMediaQueryからこれを取得することはできません(私が知る限り)。そのため、特定のプレイリスト(「過去4か月」)から取得した曲を並べ替えてから、独自のコレクションの配列を作成します。私が言うように、以下のアプローチは機能しますが、非常に遅いです。MPMediaItemPropertyAlbumTitleだけで並べ替えても、約4秒かかります(iPhone4S)。

編集:ソート記述子を試しましたが、キーを機能させることができません。例えば

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の提案により、比較ブロックを再実装して3つのソートキーをカスケードし、高次のキーが同じである場合にのみ低次のキーをチェックしました。これにより、この種の実行時間が50%以上短縮されました。それでも、私が望むほど速くはないので、誰かがより良い答えを持っているなら、それを投稿してください。

昔と新しい時代(1221アイテム)は次のとおりです。

4S実行時間=10.8、実行時間= 4.7

3GS実行時間=21.6、実行時間= 9.3

興味深いことに、配列コピーのforループからmutableCopyへの切り替えは、状況を改善するようには見えませんでした。どちらかといえば、mutableCopyはおそらく10分の1秒遅くなりました(mutableCopyでベンチマークを行った人はいますか?)。しかし、見た目がとてもきれいなので、変更を残しました。

最後に、アルバムタイトル==nilのチェックに注意してください。compareは、nil値を持つものは常にNSOrderedSameであると見なすことに注意してください。リスト内の1つのアルバムにタイトルが設定されていなかったため、このチェックなしで並べ替え順序が台無しになりました。

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 に答える