I have a few more tidbits that might help anyone else trying to integrate the iPod in OS 3.0.
After a lot of experimentation, I’ve determined that there are vastly different times that certain data takes to load into memory. You can use this to your advantage. One example, building off my last post, is that a MPMediaItem’s persistent ID (pID) loads much more quickly than it’s other properties. What this means is that, if you’re forced to load other properties from memory, you can cache the information about each item in a NSMutableDictionary with the keys being pIDs. You can then save this out to disk on applicationWillTerminate, load it in on the next run, grab an item’s pID, check the dictionary, and get a huge load-time decrease if you’ve already seen it.
Another trick that has helped me out a lot is creating an MPMediaItemCollectionWrapper class. I init one of these classes with an MPMediaItemCollection and then, in a thread-safe way, lazy-load absolutely everything. This is made easy by having every necessary property be a read only property with an overridden getter. Here’s an example:
/* Album Title */
- (NSString *) albumTitle {
@synchronized(self) {
if(albumTitle == nil) {
[self.lock lock];
NSDictionary *appInfo = [self.cache objectForKey:self.pID];
[self.lock unlock];
}
if(appInfo == nil) {
loadedFromDisk = YES;
albumTitle = [[self.representativeItem valueForProperty: MPMediaItemPropertyAlbumTitle] retain];
artist = [[self.representativeItem valueForProperty: MPMediaItemPropertyArtist] retain];
[self.lock lock];
[self.cache setObject:[NSDictionary dictionaryWithObjectsAndKeys: albumTitle, @"Title", artist, @"Artist", nil] forKey:self.persistentID];
[self.lock unlock];
} else
albumTitle = [appInfo objectForKey:@"Title"];
}
return albumTitle;
}
}
All of the wrappers share the same lock and cache, so nothing has to unnecessarily access disk. Additionally, I’ve discovered that once you access one of the non-pID properties the others come for free, so I cache both the artists and the album title at the same time. The getter for the artist looks very much the same, so the cache gets created from whichever loads first.
The other huge benefit to having a wrapper is the ability to have that albumTitle selector for sorting purposes. Apple now gives us a UILocalizedIndexCollation class to help us create a table index, but the only way to use it is if the object being sorted has a single selector from which it can be sorted.
I don’t, however, use albumTitle. I instead use this:
/* Sortable Album Title */
- (NSString *) sortableAlbumTitle {
@synchronized(self) {
if(sortableAlbumTitle == nil)
sortableAlbumTitle = [[self stringByRemovingLeadingTheFromString:self.albumTitle] retain];
return sortableAlbumTitle;
}
}
Pass that along to your collation and you can easily index all of your MPMediaItemCollections in your table in the same way Apple does (without the leading “The”).
That’s all for now. I hope this ends up helping someone else who ends up trying to recreate swaths of the iPod app in their own application.