цель c - цикл для получения изображения из iCloud последовательно - PullRequest
0 голосов
/ 22 апреля 2019

на IOS, мне нужно получить метаданные для выбранного набора изображений.Но поскольку изображения резервируются в iCloud, иногда он может сразу же вернуться (кэшироваться), а иногда это может занять секунду или две.

Цикл for проходит быстро, я могу дождаться обработки всех изображений, прежде чем двигаться вперед.Но они все еще выбираются параллельно.Как сделать так, чтобы цикл for выполнялся последовательно, ожидая завершения блока, прежде чем перейти к следующему изображению.

// Step 4: Fetch Details like Metadata for this batch
-(void) getDetailsForThisBatchOfNewAssets:(NSMutableArray*) mArrBatchOfNewAssets
                    withCompletionHandler:(blockReturnsMArrAndMArr) blockReturns{

    NSLog(@"%s with arraySize of %lu",__PRETTY_FUNCTION__, (unsigned long)[mArrBatchOfNewAssets count] );

    long assetCount = [mArrBatchOfNewAssets count];

    NSMutableArray *mArrNewAssetsAndDetails = [[NSMutableArray alloc] init];
    NSMutableArray *mArrNewAssetFailed = [[NSMutableArray alloc] init];

    if(assetCount == 0){

        NSLog(@" Looks like there are no NEW media files on the device.");
        return;
    }
    else
        NSLog(@"found %ld assets in all that need to be backed up", assetCount);

    dispatch_group_t groupForLoopGetDetails = dispatch_group_create();

    for(long i = 0 ; i < assetCount; i++){

        PHAsset *currentAsset = [[mArrBatchOfNewAssets objectAtIndex:i] objectForKey:@"asset"];

        NSString *mediaIdentifier = [[[currentAsset localIdentifier] componentsSeparatedByString:@"/"] firstObject];
        [mArrIdentifiersInThisBatch addObject:mediaIdentifier];

        dispatch_group_enter(groupForLoopGetDetails);

        [mediaManager getDetailedRecordForAsset:currentAsset
                  withCompletionHandler:^(NSMutableDictionary *mDicDetailedRecord, NSMutableDictionary *mDicRecordForError)
        {
              if(mDicRecordForError[@"error"]){
                  [mArrNewAssetFailed addObject:mDicRecordForError];

                  NSLog(@"Position %ld - Failed to fetch Asset with LocalIdentifier: %@, adding it to Failed Table. Record: %@",i,[currentAsset localIdentifier], mDicRecordForError);

              } else {
                  [mArrNewAssetsAndDetails addObject:mDicDetailedRecord ];

                  NSLog(@"Position %ld - added asset with LocalIdentifier to mArrNewAssetsAndDetails %@",i,[currentAsset localIdentifier]);
              }

            dispatch_group_leave(groupForLoopGetDetails);
        }];
    }   // end of for loop that iterates through each asset.

    dispatch_group_notify(groupForLoopGetDetails, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

        NSLog(@"Completed gathering details for this batch of assets for backup. Count : %lu and failed Media count: %lu",(unsigned long)[mArrNewAssetsAndDetails count], (unsigned long)[mArrNewAssetFailed count]);

            blockReturns(mArrNewAssetsAndDetails,mArrNewAssetFailed);
    });

}

Я просмотрел несколько вопросов по SO по этой теме, но до сих пор не понял, какчтобы сделать этот запуск последовательно.

Я не хочу делать «сам вызов» для этого метода, потому что я уже делаю «сам вызов» в другом месте, прежде чем я достигну этого метода, и мой кодтеперь из-за этого растет слишком много уведомлений и уловов.

1 Ответ

0 голосов
/ 23 апреля 2019

Предполагая, что обработчик завершения getDetailedRecordForAsset вызывается в другом потоке, вы можете использовать семафор для выполнения блока (Примечание: НЕ ДЕЛАЙТЕ это в основном потоке) внутри цикла во время ожидания обработчик завершения.

Удалите содержимое группы диспетчеризации, затем внутри цикла:

  • создайте семафор прямо перед вызовом getDetailedRecordForAsset примерно так: dispatch_semaphore_t semaphore = dispatch_semaphore_create( 0);

  • в качестве последнего оператора вызова обработчика завершения dispatch_semaphore_signal( semaphore);

  • сразу после вызова getDetailedRecordForAsset, дождитесь окончания обработчика завершения с помощью dispatch_semaphore_wait( semaphore, DISPATCH_TIME_FOREVER);

Итак, структура цикла будет выглядеть так:

for (assets)
{
    ... // get current asset, media identifier as above

    dispatch_semaphore_t semaphore = dispatch_semaphore_create( 0);

    [mediaManager getDetailedRecordForAsset:currentAsset
              withCompletionHandler:^(NSMutableDictionary *mDicDetailedRecord, NSMutableDictionary *mDicRecordForError)
        {
            ... // handle error or add asset details as above

            dispatch_semaphore_signal( semaphore);
        }
    dispatch_semaphore_wait( semaphore, DISPATCH_TIME_FOREVER);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...