我正在尝试使用
MPMediaQuery
访问用户的本地音乐库,按以下方式对结果进行排序:
Artist A (sorted alphabetically) > All of Artist A's albums, sorted alphabetically
Artist B (sorted alphabetically) > All of Artist B's albums, sorted alphabetically
Artist C (sorted alphabetically) > All of Artist C's albums, sorted alphabetically
...
我的查询结构如下:
MPMediaQuery *albumsQuery = [MPMediaQuery albumsQuery];
albumsQuery.groupingType = MPMediaGroupingAlbumArtist;
但问题是,虽然上述大部分都有效,但每个给定艺术家仅返回第一张专辑。也就是说,仅返回 Alt-J 的一张专辑,而不是库中存在的两张专辑。
这是为什么呢?我如何构建查询以返回所需的结果?
编辑:这就是我访问专辑的方式查询:
AlbumCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellID forIndexPath:indexPath];
MPMediaItemCollection *collection = [_items objectAtIndex:indexPath.row];
MPMediaItem *cellItem = [collection representativeItem];
其中
_items
是一个 NSArray,其中包含 MPMediaQuery
的结果。
对于大型库来说,David Barsky 的算法似乎超级慢。我采取了不同的方法:
-(NSArray *)albumsSortedByArtist
{
CFTimeInterval start = CACurrentMediaTime();
MPMediaQuery *albumsQuery = [MPMediaQuery albumsQuery];
NSSortDescriptor *sorter = [NSSortDescriptor sortDescriptorWithKey:@"representativeItem"
ascending:YES comparator:^NSComparisonResult(MPMediaItem * _Nonnull album1, MPMediaItem * _Nonnull album2) {
NSString *album1Name = [album1 valueForProperty:MPMediaItemPropertyAlbumArtist];
NSString *album2Name = [album2 valueForProperty:MPMediaItemPropertyAlbumArtist];
if (!album1Name || !album2Name) {
album1Name = [album1 valueForProperty:MPMediaItemPropertyArtist];
album2Name = [album2 valueForProperty:MPMediaItemPropertyArtist];
}
return [album1Name localizedStandardCompare:album2Name];
}];
NSArray *allAlbums = [albumsQuery.collections sortedArrayUsingDescriptors:@[sorter]];
NSLog(@"It took %f", CACurrentMediaTime() - start);
return allAlbums;
}
速度快多了。在具有 1161 个专辑的 iPhone 6 库上:
2016-06-07 20:28:51.620 Musica[1205:515625] Mine: 0.394556
2016-06-07 20:29:20.528 Musica[1205:515625] David Barsky's: 28.906980
您如何通过查询访问相册?有 items 方法,或者,如果我没记错的话,有 collection 方法。他们为您提供数据的方式有点不同。
显然,您可以自己手动完成这一切,只需获取所有专辑的列表并自行排序即可!
编辑我:按专辑艺术家分组意味着该集合为您提供每个专辑艺术家,然后获得代表项目基本上只是一张专辑。因此,您需要对集合进行另一个查询才能获取该艺术家的每张专辑
编辑 II:您可以使用已经找到的内容来执行其他查询,例如您已经获得的是所有不同专辑艺术家的集合。您想知道每个艺术家的专辑是什么,以便您可以使用附加谓词重复查询:
MPMediaItem* 专辑艺术家; // 之前获取的 MPMediaQuery* albumQuery = [MPMediaQuery albumsQuery]; MPMediaPropertyPredicate* albumPredicate = [MPMediaPropertyPredicate predicateWithValue: [albumArtist valueForProperty: MPMediaItemPropertyAlbumArtist] forProperty: MPMediaItemPropertyAlbumArtist]; [albumQuery addFilterPredicate: albumPredicate]; NSArray* allAlbums = [albumQuery 集合];
以下作品(慢慢地,在一个相当大的音乐库上。您的结果可能会有所不同)。感谢 CMash 的帮助。
- (NSArray *)queryForMusic {
NSMutableArray *allAlbums = [[NSMutableArray alloc] init];
MPMediaQuery *artistsQuery = [MPMediaQuery artistsQuery];
artistsQuery.groupingType = MPMediaGroupingAlbumArtist;
NSArray *allArtists = [artistsQuery collections];
for (MPMediaItemCollection *collection in allArtists) {
MPMediaItem *albumArtist = [collection representativeItem];
MPMediaQuery *albumQuery = [MPMediaQuery albumsQuery];
MPMediaPropertyPredicate* albumPredicate = [MPMediaPropertyPredicate predicateWithValue: [albumArtist valueForProperty: MPMediaItemPropertyAlbumArtist] forProperty: MPMediaItemPropertyAlbumArtist];
[albumQuery addFilterPredicate: albumPredicate];
NSArray *artistsAblums = [albumQuery collections];
[allAlbums addObjectsFromArray:artistsAblums];
}
return allAlbums;
}
我尝试制作 Adam 代码的 Swift 版本,到目前为止似乎可行。目前,它似乎按字母顺序降序对艺术家进行排序,但尚未对其进行太多测试,因此可能需要对某些比较结果的处理等进行一些调整。
let query = MPMediaQuery.albums()
let collections: [MPMediaItemCollection]? = query.collections?.sorted(by: { collection1, collection2 in
var album1Name: String?
var album2Name: String?
let properties: [String] = [
MPMediaItemPropertyAlbumArtist,
MPMediaItemPropertyArtist
]
for prop in properties {
if let str = collection1.representativeItem?.value(forProperty: prop) as? String {
album1Name = str
break
}
}
for prop in properties {
if let str = collection2.representativeItem?.value(forProperty: prop) as? String {
album2Name = str
break
}
}
let comparison: ComparisonResult
if let album1Name, let album2Name {
comparison = album1Name.localizedStandardCompare(album2Name)
}
else {
comparison = .orderedSame
}
let result: Bool
switch comparison {
case .orderedAscending:
result = true
case .orderedSame, .orderedDescending:
result = false
}
return result
})