开发者

ALAssetsLibrary enumerateGroupsWithTypes: - Thread synchronization

I'm using [ALAssetsLibrary enumerateGroupsWithTypes:] to store the ALAssets in an array. As this is an asynchronous operation, I need to wait for it to finish before continuing my work.

I read Cocoa thread synchronisation when using [ALAssetsLibrary enumerateGroupsWithTypes:] and tried the recommended NSConditionLock. However, the blocks are always performed in the main thread, thus if I wait using the conditionl开发者_高级运维ock, the main thread is blocked and the blocks won't get executed -> I'm stuck. I even tried running the method loadAssets on a new thread, but still the blocks get executed on the main thread.

I can't find a way to actually wait for the enumeration to finish. Is there a way to force the blocks to a different thread than the main thread or anything else I can do?

Here's the code:

- (void)loadAssets
{
    assets = [NSMutableArray array];
    NSConditionLock *threadLock = [[NSConditionLock alloc] initWithCondition:THREADRUNNING];

    void (^assetEnumerator)(ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop)
    {
        if(result != nil)
        {
            [assets addObject:result];
        }
    };

    void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop)
    {
        if(group != nil)
        {
            [group enumerateAssetsUsingBlock:assetEnumerator];
        }

        [threadLock lock];
        [threadLock unlockWithCondition:THREADFINISHED];
    };

    void (^assetFailureBlock)(NSError *) = ^(NSError *error)
    {
        [threadLock lock];
        [threadLock unlockWithCondition:THREADFINISHED];
    };

    ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
    [assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:assetGroupEnumerator failureBlock:assetFailureBlock];

    [threadLock lockWhenCondition:THREADFINISHED];
    [threadLock unlock];

    [assetsLibrary release];
    [threadLock release];
}


you are killing your assetsLibrary object before it finished to enumrate the objects. move it to your .h file and release it in dealloc.


I know this thread is probably dead, but I'm answering it because this is where I landed by Googling

The trick is to lock your background thread until the enumeration yields a nil-group. This category is one example of how to use it, you can use the category method as a drop-in replacement of the ALAssetsLibrary enumeration method.

@implementation ALAssetsLibrary (EEEConcurrency)

- (NSUInteger)eee_enumerateGroupsLockedWithTypes:(ALAssetsGroupType)types
                                      usingBlock:(ALAssetsLibraryGroupsEnumerationResultsBlock)enumerationBlock
                                    failureBlock:(ALAssetsLibraryAccessFailureBlock)failureBlock
{
    NSAssert(![NSThread isMainThread], @"This would create a deadlock (main thread waiting for main thread to complete)");

    enum
    {
        EEEAssetsLibraryDone,
        EEEAssetsLibraryBusy
    };

    NSConditionLock *assetsLibraryConditionLock = [[NSConditionLock alloc] initWithCondition:EEEAssetsLibraryBusy];

    __block NSUInteger numberOfGroups = 0;
    [self enumerateGroupsWithTypes:types
                        usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
                            enumerationBlock(group, stop);
                            if (group) numberOfGroups++;
                            if (!group || *stop)
                            {
                                [assetsLibraryConditionLock lock];
                                [assetsLibraryConditionLock unlockWithCondition:EEEAssetsLibraryDone];
                            }
                        }
                      failureBlock:^(NSError *error) {
                          failureBlock(error);
                          [assetsLibraryConditionLock lock];
                          [assetsLibraryConditionLock unlockWithCondition:EEEAssetsLibraryDone];
                      }];

    [assetsLibraryConditionLock lockWhenCondition:EEEAssetsLibraryDone];
    [assetsLibraryConditionLock unlock];

    return numberOfGroups;
}

@end

Download the category at https://gist.github.com/epologee/8890692


This code chunk should work for you -->

    ALAssetsLibrary *assetsLib = [[ALAssetsLibrary alloc] init];
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    __block int numberOfGroups = 0;

    dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [assetsLib enumerateGroupsWithTypes:ALAssetsGroupAlbum usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
            if (group) {
                numberOfGroups++;
            }
            else {
                dispatch_semaphore_signal(sema);
            }
        } failureBlock:^(NSError *error) {
            NSLog(@"enumerateGroupsWithTypes failure %@", [error localizedDescription]);
            dispatch_semaphore_signal(sema);
        }];
    });

    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    NSLog( @"number of groups is: %d", numGroups);

Although instead of DISPATCH_TIME_FOREVER you may want to make the time one second from now


dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        _assetsLibrary = [[ALAssetsLibrary alloc] init];


        ALAssetsLibraryGroupsEnumerationResultsBlock listGroupBlock = ^(ALAssetsGroup *group, BOOL *stop) {
            if (group)
            {
                if (((NSString *)[group valueForProperty:ALAssetsGroupPropertyType]).intValue == ALAssetsGroupAlbum)
                {
                    [albumSettingsList addObject:group];
                } else {
                    dispatch_semaphore_signal(sema);
                }
            }
        };

        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError *error) {

            switch ([error code]) {
                case ALAssetsLibraryAccessUserDeniedError:
                case ALAssetsLibraryAccessGloballyDeniedError:
                    break;
                default:
                    break;
            }
            dispatch_semaphore_signal(sema);
        };

        NSUInteger groupTypes = ALAssetsGroupAlbum | ALAssetsGroupEvent | ALAssetsGroupFaces | ALAssetsGroupSavedPhotos;
        [self.assetsLibrary enumerateGroupsWithTypes:groupTypes usingBlock:listGroupBlock failureBlock:failureBlock];
    });
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

whenever you want to get album list synchoronos with IOS 7


Use dispatch_semaphore_t to control it

dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    [assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll
                                 usingBlock:^(ALAssetsGroup *assetsGroup, BOOL *stop) {
                                     if (assetsGroup) {
                                         // Filter the assets group
                                         [assetsGroup setAssetsFilter:[ALAssetsFilter allAssets]];
                                         // Add assets group
                                         if (assetsGroup.numberOfAssets > 0) {
                                             // Add assets group
                                             DNAlbum *album = [DNAlbum albumWithAssetGroup:assetsGroup];
                                             [albumArray addObject:album];
                                         }
                                     }
                                     if (*stop || !assetsGroup) {
                                         dispatch_semaphore_signal(sem);
                                     }
                                 } failureBlock:^(NSError *error) {
                                     dispatch_semaphore_signal(sem);
                                 }];
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜