How to find an specific key/value (property list)
I'm learning cocoa/objective-c. Right now I'm dealing with key/value coding. After reading Aaron's book and other sources, I thought that I was able to left the simple examples and try a complex one...
I'm trying read iTunes property list (iTunes Music Library.xml). I would like to retrieve the tracks held by an specific playlist.
Probably everybody knows it, but bellow I put a piece of the xml:
<plist version="1.0">
<dict>
<key>Major Version</key><integer>1</integer>
...
<key>Playlists</key>
<array>
<dict>
<key>Name</key><string>Library</string>
<key>Master</key><true/>
<key>Playlist ID</key><integer>20117</integer>
...
<key>Playlist Items</key>
<array>
<dict>
<key>Track ID</key><integer>10281</integer>
</dict>
<dict>
<key>Track ID</key><integer>10283</integer>
</dict>
<dict>
<key>Track ID</key><integer>10285</integer>
</dict>
...
</array>
</dict>
<dict>
<key>Name</key><string>Classical Music</string>
<key>Playlist ID</key><integer>45013</integer>
...
</dict>
</array>
</dict>
</plist>
As you can see, the playlists are stored as dictionaries inside an array, and the key that identifies it is inside it, not as a <key>
preceding it.
The problem is that I'm not able to figure out how to search for a key that is inside another one.
With the following code I can find the the array in which the playlists are stored, but how to find an specific <dict>
? In above plist, the dictionary has 3 keys to identify it: name, master and id. The first playlist has the id 20117 and de second 45013. How to get the tracks of playlist 20117?
NSDictionary *rootDict = [[NSDiction开发者_如何学Cary alloc] initWithContentsOfFile:file];
NSArray *playlists = [rootDict objectForKey:@"Playlists"];
Here at Stackoverflow I found this post, but I'm not sure if iterate over the array and test it is a good idea.
I'm quite sure that I could use valueForKeyPath
, but I'm unable to figure out how to do it.
Any help is welcome.
TIA,
Bob
Supposing you want to search the "Playlist ID" == 12194:
NSString *path = [[NSBundle mainBundle] pathForResource:@"iTunes Music Library" ofType:@"xml"];
NSDictionary *rootDict = [[NSDictionary alloc] initWithContentsOfFile:path];
NSArray *playlists = [rootDict objectForKey:@"Playlists"];
NSPredicate *pred = [NSPredicate predicateWithFormat:@"%K == %@", @"Playlist ID",
[NSNumber numberWithInt:12194]];
NSArray *filteredArray = [playlists filteredArrayUsingPredicate:pred];
for (NSDictionary *dict in filteredArray) {
NSLog(@"Name = %@", [dict valueForKey:@"Name"]);
NSLog(@"Playlist ID = %@", [dict valueForKey:@"Playlist ID"]);
}
Note the fast enumeration, in this case, would return only one record (if any)
As it turns out, NSFastEnumeration (the one where you say for (NSDictionary *playlist in Playlists)
is quite, well, fast. See here for details. If for some crazy reason you really don't want to do that, you can use - (NSUInteger)indexOfObjectPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate
, but that probably iterates over the array anyway. NSPredicate stuff was more or less designed to handle this type of thing, but they are confusing and limited. Basically iterating over things is really fast, because barring large database style optimizations, filtering abstractions usually end up iterating anyway (wasting efficiency by making you construct+destroy+interface with various objects).
see the -propertyList
method of NSString
.
精彩评论