Mason G. Zhwiti Mason G. Zhwiti - 1 year ago 60
iOS Question

What's the fastest way in iOS to retrieve the number of songs for a specific artist?

I am trying to retrieve all the artists on the local iOS device, and for each artist, the number of songs available for that artist.

I currently am doing this in a straight-forward fashion, by querying for all artists, and for each artist, counting the number of items (songs) in its collection:

MPMediaQuery *query = [[MPMediaQuery alloc] init];
[query setGroupingType:MPMediaGroupingArtist];
NSArray *collections = [query collections];
for (MPMediaItemCollection *collection in collections)
MPMediaItem *representativeItem = [collection representativeItem];
int songs = [[collection items] count];
// do stuff here with the number of songs for this artist

However, this doesn't seem very efficient, or at least, it's slower than I had anticipated.

On a demo iPhone 4 device with several hundred artists, the above code took about 7 seconds to run. When I commented out the line that obtains the count of "collection items," the time is reduced to 1 second.

So I am wondering if there is a faster way to retrieve the song counts for artists than what I am doing above?

Update 09/27/2011. I see that I can simplify the song count retrieval for an artist using this:

int songs = [collection count];

Rather than what I was doing:

int songs = [[collection items] count];

However, in reality this has had little effect on performance.

I borrowed an iPhone 3G to try the performance of this issue on a slower device.

My code takes 17.5 seconds to run on this 3G with only 637 songs spread across 308 artists.

If I comment out the line that retrieves the number of songs, the same device finishes in only 0.7 seconds...

There must be a faster way to retrieve number of songs per artist on an iOS device.

Answer Source

After further research and trial and error, I believe the fastest way is to query the media library using an artistsQuery, and instead of looping through each artist's collection, you keep track of the number of songs per artist using an NSMutableDictionary of NSNumbers.

Using the code below, I'm seeing a speed improvement of 1.5x to 7x over my initial approach, depending on the device speed, number of artists, and number of songs per artist. (Biggest increase was an iPhone 3G which was taking 21.5 seconds for 945 songs initially, and now takes 2.7 seconds!)

I will edit this answer if I discover any speed improvements. Please feel free to correct anything directly in my answer, as I am still new to Objective-C and the iOS APIs. (In particular, I might be missing a faster way to store integers in a hash table than what I've got below with NSNumbers in an NSMutableDictionary?)

NSMutableDictionary *artists = [[NSMutableDictionary alloc] init]; 
MPMediaQuery *query = [MPMediaQuery artistsQuery];
NSArray *items = [query items];
for (MPMediaItem *item in items)
     NSString *artistName = [item valueForProperty:MPMediaItemPropertyArtist];

    if (artistName != nil)
        // retrieve current number of songs (could be nil)
        int numSongs = [(NSNumber*)[artists objectForKey:artistName] intValue];

        // increment the counter (could be set to 1 if numSongs was nil)

        // store the new count
        [artists setObject:[NSNumber numberWithInt:numSongs] forKey:artistName];
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download