11

如何以与 iOS 音乐应用程序相同的方式搜索 iPod 库?我想进行一般查询,返回每个艺术家、专辑和歌曲的结果。例如,如果我搜索 Kenny Chesney,我希望歌曲查询返回所有 Kenny Chesney 歌曲(以及其中包含 Kenny Chesney 的任何歌曲标题或专辑。)当我进行此查询和每个属性的谓词(歌曲标题、专辑标题,艺术家姓名),返回一个空数组。

这是一些代码,可以让您更好地了解我正在尝试完成的工作:

MPMediaPropertyPredicate *songPredicate =
[MPMediaPropertyPredicate predicateWithValue:searchText
                                 forProperty:MPMediaItemPropertyTitle
                              comparisonType:MPMediaPredicateComparisonContains];

MPMediaPropertyPredicate *albumPredicate =
[MPMediaPropertyPredicate predicateWithValue:searchText
                                 forProperty:MPMediaItemPropertyAlbumTitle
                              comparisonType:MPMediaPredicateComparisonContains];

MPMediaPropertyPredicate *artistPredicate =
[MPMediaPropertyPredicate predicateWithValue:searchText
                                 forProperty:MPMediaItemPropertyArtist
                              comparisonType:MPMediaPredicateComparisonContains];

MPMediaQuery *songsQuery = [MPMediaQuery songsQuery];
[songsQuery addFilterPredicate:songNamePredicate];
[songsQuery addFilterPredicate:artistNamePredicate];
[songsQuery addFilterPredicate:albumNamePredicate];

NSLog(@"%@", [songsQuery items]);

我通过分别对每个谓词运行查询来实现这一点,但这似乎非常低效!

4

4 回答 4

16

以这种方式组合您的谓词使其类似于“AND”关系。这意味着您正在查询的歌曲的标题、专辑和名称都与搜索文本匹配。

为了实现您想要做的事情,您应该运行 3 个查询并以适当的方式组合结果。

如果你运行:

MPMediaPropertyPredicate *artistPredicate =
[MPMediaPropertyPredicate predicateWithValue:searchText
                                 forProperty:MPMediaItemPropertyArtist
                              comparisonType:MPMediaPredicateComparisonContains];

NSSet *predicates = [NSSet setWithObjects: artistPredicate, nil];

MPMediaQuery *songsQuery =  [[MPMediaQuery alloc] initWithFilterPredicates: predicates];

NSLog(@"%@", [songsQuery items]);

这将为您返回与您的搜索匹配的艺术家。你应该对歌曲和专辑做同样的事情。

如果您这样做很慢,您可以一次检索所有媒体并手动过滤:

MPMediaQuery *everything = [[MPMediaQuery alloc] init];

NSLog(@"Logging items from a generic query...");
NSArray *itemsFromGenericQuery = [everything items];
for (MPMediaItem *song in itemsFromGenericQuery) {
    NSString *songTitle = [song valueForProperty: MPMediaItemPropertyTitle];
    /* Filter found songs here manually */
}
于 2013-02-06T12:31:54.610 回答
11

这对我有用:

MPMediaQuery *searchQuery = [[MPMediaQuery alloc] init];
NSPredicate *test = [NSPredicate predicateWithFormat:@"title contains[cd] %@ OR albumTitle contains[cd] %@ OR artist contains[cd] %@", searchString, searchString, searchString];
NSArray *filteredArray = [[searchQuery items] filteredArrayUsingPredicate:test];

//NSLog(@"%@", [filteredArray valueForKeyPath:@"title"]);

for (MPMediaItem *song in filteredArray) 
{
    [arrayOfSongItems addObject:song];
}

我基本上在从媒体查询中获取所有项目后进行过滤。我认为我的解决方案并不比首先过滤查询更好,但绝对比单独搜索三次更好。或者多次遍历数组。

于 2013-02-06T15:26:21.337 回答
2

这里有两种方法:

  1. 使用多个 MPMediaPropertyPredicates 来使用查询获取所有内容。使用这种方法,您将需要执行多个查询并自己汇总结果。NSSet 是你的朋友!

  2. 从库中获取所有内容(或接近它),然后进行搜索或过滤。

在旧设备或操作系统版本上访问音乐库可能非常慢。根据我自己实现与您所描述的内容非常相似的经验,我使用方法 2 获得了最佳结果。一旦我拥有了几乎所有内容,然后我使用分散/收集方法迭代这些项目(我的需求不允许为此使用 NSPredicate)。对我来说,这实际上比方法 1 的性能要好得多,尽管我知道在 iOS 6 中这个差距已经缩小了一些。

于 2013-02-13T05:34:25.617 回答
2

运行查询后过滤项目的 Swift 3+ 解决方案,类似于Mohammed Habib 的回答

let searchString = “string to search”
let query = MPMediaQuery()

let filteredItems = query.items?.filter { item -> Bool in
    let properties = [item.songTitle,
                      item.artist,
                      item.albumTitle]

    let lowercasedProperties = properties.compactMap { $0.lowercased() }

    return lowercasedProperties.contains(searchString.lowercased())
}

print(filteredItems ?? [])
于 2018-08-06T09:58:20.230 回答