Search code examples
objective-cios7grand-central-dispatchmpmediaquery

Running MPMediaQuery in GCD


The following code runs great and gives me the results I am looking for. However, I would like to run it in its own thread. Is MPMediaQuery thread safe, and what am I doing wrong, if it is?

-(NSArray*) mediaItemsFromPersistentIds:(NSArray*) mediaPersistentIds
{
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }

       MPMediaQuery *mediaQuery = [MPMediaQuery new];
       NSArray *itemsmediaQuery = mediaQuery.items;
       NSPredicate *predicate   = [NSPredicate predicateWithFormat:@"%K IN %@", @"itemId", mediaPersistentIds];

    return [itemsmediaQuery filteredArrayUsingPredicate:predicate];
}

When I try the following, I get

Terminating app due to uncaught exception 'MPMediaItemCollectionInitException', reason: 'items array must not be empty'

I know the [itemsmediaQuery filteredArrayUsingPredicate:predicate] is being returned as (null)

-(NSArray*) mediaItemsFromPersistentIds:(NSArray*) mediaPersistentIds
{
    if (debug==1) {
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    }
    __block NSArray *itemsmediaQuery;
    __block NSPredicate *predicate;

    dispatch_queue_t mediaQueryQueue = dispatch_queue_create("media query", NULL);
    dispatch_async(mediaQueryQueue, ^{

        MPMediaQuery *mediaQuery      = [MPMediaQuery new];
        itemsmediaQuery = mediaQuery.items;
        predicate = [NSPredicate predicateWithFormat:@"%K IN %@", @"itemId", mediaPersistentIds];

    });

    return [itemsmediaQuery filteredArrayUsingPredicate:predicate];
}

Solution

  • It is safe to request these items in the background.

    Right now, you're not actually running the query in the background. You could do something like this:

    - (void)mediaItemsFromPersistentIds:(NSArray*)ids
                               callback:(void (^)(NSArray *items))callback {
        dispatch_queue_t mediaQueryQueue = dispatch_queue_create("media query", NULL);
        dispatch_async(mediaQueryQueue, ^{
            MPMediaQuery *mediaQuery = [MPMediaQuery new];
            itemsmediaQuery = mediaQuery.items;
            predicate = [NSPredicate predicateWithFormat:@"%K IN %@", @"itemId", ids];
    
            // Do the query
            NSArray *items = [itemsmediaQuery filteredArrayUsingPredicate:predicate];
    
            // Post the query results to the main thread in some way
            dispatch_async(dispatch_get_main_queue(), ^{
                // You could pass this off to a delegate or callback block
                if (callback)
                    callback(items);
            });
        });
    }
    

    And to call it:

    NSArray *ids = ...
    [someObj mediaItemsFromPersistentIds:ids callback:^(NSArray *items) {
        // Do something with `items`
    }];