5

[ALAssetsLibrary enumerateGroupsWithTypes:] を使用して、ALAssets を配列に格納しています。これは非同期操作であるため、作業を続行する前に完了するのを待つ必要があります。

[ALAssetsLibrary enumerateGroupsWithTypes:] を使用する場合の Cocoa スレッド同期を読み、推奨される 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];
}
4

5 に答える 5

1

このスレッドはおそらく死んでいることは知っていますが、これは私がグーグルで上陸した場所なので答えています

秘訣は、列挙によって nil-group が生成されるまでバックグラウンド スレッドをロックすることです。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でカテゴリをダウンロードします

于 2014-02-08T21:39:06.823 に答える
1

オブジェクトの列挙が完了する前に、assetsLibrary オブジェクトを強制終了しています。それを .h ファイルに移動し、dealloc で解放します。

于 2011-08-21T10:44:18.053 に答える
0

このコードチャンクはあなたのために働くはずです -->

    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 の代わりに、今から 1 秒後の時刻にしたいかもしれませんが

于 2014-09-23T19:41:13.517 に答える
0

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);
于 2018-10-10T06:39:25.507 に答える