Using the iPod Library

使用iPod库

你的应用程序或许要比媒体项选择器需要更多地控制来管理和选择媒体项。如果你想要提供一个定制的用户界面到设备的iPod库、执行特殊查询、或是将媒体项定制的元数据联合起来,你都需要用到这个API的数据库访问类。

图 4-1 说明了应用程序和数据库访问类如何影响检索媒体项。

图 4-1 使用iPod库数据库访问类

首先,花点时间注意这个图和Figure 1-5之间的区别。之前的图帮助解释设么事查询。这个图表明了媒体查询类在这个群组中的位置,显示了所有数据库访问类是如何相互联系的。

图中说明了两种应用程序和设备iPod库之间相互关系的场景。首先,从“Your application”图标逆时针方向移动,这个图描述了创建和配置一个定义一个媒体项集合的查询。这个集合选项说明来自库的项目的子集。尽管没有显示在图中,但是集合是调用查询的返回值。每个媒体项拥有一个媒体项插图对象,如图中所示,在他的其他属性中。

图4-1第二个场景是应用程序从iPod库接收通过MPMediaLibrary类得到的改变通知。通过注册获得这些改变通知,如果用户在应用程序运行的时候同步他们的设备,应用程序能够更新任何储存在库里的内容。

Retrieving Ungrouped Media Items

检索未分组的媒体项


通过构建一个媒体查询开始,从设备iPod库检索媒体项。最简单的查询是通用的 “everything”查询,如代码清单4-1所示,它匹配整个库里所包含的内容。然后,这个例子记录这些媒体项的标题到Xcode调试器控制台,演示使用 items 的属性来调用查询,并且检索匹配的媒体项。

代码清单 4-1  创建和使用一个一般的媒体查询

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];


   NSLog (@"%@", songTitle);


}


Note: 和本文档的所有例题一样,这个例题也只能使用在真机上而不能使用在模拟器上。


想要构建一个更加具体的查询,需要应用一个或多个媒体属性断言到一般查询。一个断言指定一个逻辑条件来测试媒体项。

代码清单4-2创建一个包含媒体项的“艺术家”属性条件的断言必须有一个特定值。这个清单添加了一个断言到查询。

Listing 4-2  创建并应用媒体属性断言

MPMediaPropertyPredicate *artistNamePredicate =

   [MPMediaPropertyPredicate predicateWithValue: @"Happy the Clown"

forProperty: MPMediaItemPropertyArtist];


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


[myArtistQuery addFilterPredicate: artistNamePredicate];


NSArray *itemsFromArtistQuery = [myArtistQuery items];


如果你运行这段代码, itemsFromArtistQuery 数组将仅包含从iPod库中有Happy the Clown的项目。

你能够构建和添加多个断言到查询来缩减查询的匹配项目。代码清单4-3显示了使用两个断言的技巧。

代码清单 4-3  应用多个断言到现有的媒体查询

MPMediaPropertyPredicate *artistNamePredicate =

   [MPMediaPropertyPredicate predicateWithValue: @"Sad the Joker"

   forProperty: MPMediaItemPropertyArtist];


MPMediaPropertyPredicate *albumNamePredicate =

   [MPMediaPropertyPredicate predicateWithValue: @"Stair Tumbling"

   forProperty: MPMediaItemPropertyAlbumTitle];


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


[myComplexQuery addFilterPredicate: artistNamePredicate];


[myComplexQuery addFilterPredicate: albumNamePredicate];


你创建每个断言使用你选择值(例如艺术家名字),这些值都有恰当的属性键。这些键的详细面熟在 MPMediaItem Class Reference中的 General Media Item Property KeysPodcast Item Property Keys

当你应用超过一个的断言到查询中时,这个查询使用逻辑操作符“AND”结合它们。

Important:不要给特定的媒体项属性多应用多个断言。例如,不要指定两个 MPMediaItemPropertyArtist 断言到查询。如果你这样做,那么根据使用查询的行为,所得的结果是未定义。


你也能在查询初始化的时候添加断言,如代码清单4-4所示。(在这个例子中的两个断言假设是之前已定义的。)

代码清单 4-4  当初始化媒体查询的时候应用多个断言

NSSet *predicates =

   [NSSet setWithObjects: artistNamePredicate, albumNamePredicate, nil];


MPMediaQuery *specificQuery =

   [[MPMediaQuery alloc] initWithFilterPredicates: predicates];


代码清单4-4首先定义了一个 NSSet 对象,这个对象包含了两个断言。然后使用initWithFilterPredicates: 类方法分配和初始化媒体查询。

仅有某些属性键能够被作为有效的断言。这些键在MPMediaItem Class Reference中被标记为“过滤性”。如果你试图使用一个包含无效断言的查询,那么结果将是未定义的(undefined)。

Important: 系统允许你使用属性键(这些键对于使用断言是没有意义的,that are not meaningful for use with predicates)创建断言。如果你试图应用这样的断言到查询,那么所得的结果是未定义的。想要避免这样的问题,采取如下方式:


仔细阅读 MPMediaItem Class Reference 文档。

代码防御,在使用媒体项之前先通过使用 canFilterByProperty:方法来来验证他们。

不要让用户定义属性断言。

通过彻底测试你的代码来确保他们的行为符合你对它们的期望。


代码清单4-5展示了如何使用canFilterByProperty: 类方法在使用断言前来验证媒体项属性键。

代码清单 4-5  测试是否一个属性项能够使用在一个媒体属性断言

if ([MPMediaItem canFilterByProperty: MPMediaItemPropertyGenre]) {


   MPMediaPropertyPredicate *rockPredicate =

       [MPMediaPropertyPredicate predicateWithValue: @"Rock"

       forProperty: MPMediaItemPropertyGenre];


   [query addFilterPredicate: rockPredicate];


}


在代码清单4-5中,只有在指定的媒体项属性键(在这个例子中是 MPMediaItemPropertyGenre)能够被用来创建一个有效的断言的时候,if语句的函数体才会被执行。苹果建议你总是在构建一个媒体属性断言前执行这样的检查。

Retrieving Media Item Collections

检索媒体项集合

媒体查询不仅在检索未分组的媒体项时有用。你也可以使用媒体查询来检索排序和安排媒体项集合。这个安排取决于你设置的媒体查询的grouping 属性的值。

代码清单4-6展示了如何通过特定的艺术家来检索所有的歌曲,将这些歌曲安排进一个专辑。这个例子在Xcode调试器控制台记录结果。

代码清单 4-6  使用grouping类型指定媒体项集合

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


[query addFilterPredicate: [MPMediaPropertyPredicate

                              predicateWithValue: @"Moribund the Squirrel"

                                     forProperty: MPMediaItemPropertyArtist]];


// Sets the grouping type for the media query


[query setGroupingType: MPMediaGroupingAlbum];


NSArray *albums = [query collections];


for (MPMediaItemCollection *album in albums) {

 MPMediaItem *representativeItem = [album representativeItem];


   NSString *artistName =

       [representativeItem valueForProperty: MPMediaItemPropertyArtist];


   NSString *albumName =

       [representativeItem valueForProperty: MPMediaItemPropertyAlbumTitle];


   NSLog (@"%@ by %@", albumName, artistName);


   NSArray *songs = [album items];


   for (MPMediaItem *song in songs) {


       NSString *songTitle =

           [song valueForProperty: MPMediaItemPropertyTitle];


       NSLog (@"\t\t%@", songTitle);


   }

}


从代码清单4-6你可以看出,媒体查询的collections 属性的值是一个数组的数组。外for循环遍历指定艺术家的专辑。内for循环遍历当前专辑里的歌曲。

MPMediaQuery 类包括几个方便的构造函数来创建带有预配置grouping类型的查询。下面例子中的语句,是一个附加“专辑”分组类型的新分配的查询。

MPMediaQuery *query = [MPMediaQuery albumsQuery];


关于所有方便的构造函数的描述,详见 MPMediaQuery Class Reference.

Using Media Item Artwork

使用媒体项插图

一个最有用且有强烈感染力的属性是媒体项的插图。想要显示插图,你要在Xcode上使用IB。步骤如下:

1.  添加一个UIImageView 对象到你的IB的视图布局。

2.添加一个 IBOutlet势力变量到你的视图控制器类来连接 UIImageView对象。

3.从拥有插图的媒体项检索插图(用本节前面描述的方法检索媒体项)。

4.将插图转换为UIImage对象,然后分配到你的视图布局的 UIImageView 对象。


代码清单 4-7 展示了第3、4步的操作。

代码清单 4-7  显示媒体项的专辑插图

MPMediaItemArtwork *artwork =

   [mediaItem valueForProperty: MPMediaItemPropertyArtwork];


UIImage *artworkImage =

   [artwork p_w_picpathWithSize: albumImageView.bounds.size];

if (artworkImage) {

   albumImageView.p_w_picpath = artworkImage;


}

else {


   albumImageView.p_w_picpath = [UIImage p_w_picpathNamed: @"noArtwork.png"];


}


在代码清单4-7的最后一行的noArtwork.png 文件是你添加到Xcode工程上的备用图,在媒体项没有关联的插图的时候使用。