ALAssetsLibrary enumerateGroupsWithTypes: - синхронизация потоков - PullRequest
5 голосов
/ 06 июня 2011

Я использую [ALAssetsLibrary enumerateGroupsWithTypes:] для хранения ALAssets в массиве. Поскольку это асинхронная операция, мне нужно дождаться ее завершения, прежде чем продолжить работу.

Я прочитал Синхронизация потоков какао при использовании [ALAssetsLibrary enumerateGroupsWithTypes:] и попробовал рекомендованный NSConditionLock. Однако блоки всегда выполняются в главном потоке, поэтому, если я подожду, используя условную блокировку, основной поток будет заблокирован, и блоки не будут выполнены -> Я застрял. Я даже пытался запустить метод loadAssets в новом потоке, но блоки все равно выполняются в основном потоке.

Я не могу найти способ фактически дождаться окончания перечисления. Есть ли способ заставить блоки в другой поток, чем основной поток или что-нибудь еще, что я могу сделать?

Вот код:

- (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];
}

Ответы [ 5 ]

2 голосов
/ 09 февраля 2014

Я знаю, что эта тема, вероятно, мертва, но я отвечаю на нее, потому что это то место, где я приземлился с помощью Googling

Хитрость заключается в том, чтобы заблокировать ваш фоновый поток, пока перечисление не даст нулевую группу. Эта категория является одним из примеров того, как ее использовать. Вы можете использовать метод категории как замену метода перечисления ALAssetsLibrary.

@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

Скачать категорию на https://gist.github.com/epologee/8890692

1 голос
/ 21 августа 2011

вы убиваете свой объект assetsLibrary до того, как он закончил перечислять объекты. переместите его в свой файл .h и выпустите его в dealloc.

0 голосов
/ 10 октября 2018

Используйте dispatch_semaphore_t для управления им

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 голосов
/ 03 июля 2018
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);

всякий раз, когда вы хотите получить список синхронизированных альбомов с IOS 7

0 голосов
/ 23 сентября 2014

Этот фрагмент кода должен работать для вас ->

    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);

Хотя вместо DISPATCH_TIME_FOREVER вы можете использовать время на одну секунду с этого момента

...