AssetLibrary not return all assets with "ALAssetsGroupAll"

717 views Asked by At

I am querying the asset library with the following code

ALAssetsLibrary *assetsLibrary = [self defaultAssetsLibrary];
[assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
    NSMutableArray *tmpAssets = [@[] mutableCopy];
    [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
        if(result)
        {
            [tmpAssets addObject:result];
        }
    }];

    NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO];
    finished([[tmpAssets sortedArrayUsingDescriptors:@[sort]]  mutableCopy]);

} failureBlock:^(NSError *error) {
    finished(@[]);
    NSLog(@"Error loading images %@", error);
}];

However it seems that I am not getting all of the assets, if I add images to the iPhone from an external source these are not showing in the list of assets received from the above code... I am getting what seems like everything else though. I suspected it could be a limitations of the framework but when I use instagram I noticed that the photos which were missing in my app were visible... How do i get every type of asset "ALAssetsGroupAll" not enough?

2

There are 2 answers

0
matt On BEST ANSWER

The problem is that you're not understanding how enumerateAssetsUsingBlock: works. It is asynchronous.

To see what I mean by that, let me divide up your code using some numbers:

// (1)
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
    // (2)
    if(result)
    {
        [tmpAssets addObject:result];
    }
}];
// (3)
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO];
finished([[tmpAssets sortedArrayUsingDescriptors:@[sort]]  mutableCopy]);

The problem is that 3 executes before 2. Thus there is nothing in tmpAssets yet.

So what are you supposed to do about this? Well, this method (and other ALAssets methods that work similarly) operate in a very strange and special way: they call their block one extra time, with a nil argument. (You seem to have realized this, since you are doing a nil test; but you have not understood what the implications are.) Your job is to test for a nil parameter. If the parameter is nil, this is the final extra call, and now you can do any cleanup. So, like this:

// (1)
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
    // (2)
    if(result)
    {
        [tmpAssets addObject:result];
    }
    else
    // (3) // aha, finished, this is the extra time through
    {
        // NOW do something with tmpAssets!
    }
}];
0
nort On

It seems like you need to add all of the assets into a single array from all of the groups instead of for the groups individually with multiple calls to the finished block.

-(NSArray *)allAssets {
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    NSMutableArray *allAssets = [@[] mutableCopy];

    [[self defaultAssetsLibrary] enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
        [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
            if(result)
                [tmpAssets addObject:result];
        }];

        dispatch_semaphore_signal(semaphore);
    } failureBlock:^(NSError *error) {
        NSLog(@"Error loading images %@", error);
        dispatch_semaphore_signal(semaphore);
    }];

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO];
    return [tmpAssets sortedArrayUsingDescriptors:@[sort]];
}