Как заставить определенную часть функции ждать в iOS

Я пытаюсь выполнить операцию общего доступа, где я вызываю функцию с асинхронным блоком, но в моем следующем операторе if мне нужно получить значение, которое завершается в блоке, чтобы продолжить. Это мой код, который выделит больше деталей. Я слышал о NSLock и пытался использовать его, но он не работал, может быть, я делаю что-то блокировку, я не очень знаком с блокировками.

-(void) shareOperation
{
__block NSString *resultText;
BOOL continueSharing;
 NSLock *conditionLock=[[NSLock alloc] init];
         dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(queue, ^{
            [conditionLock lock];
        [self performSomeAsynchronousOperation completionBlock:^(NSError *tError, bool status)
         {
             dispatch_async(dispatch_get_main_queue(),
                            ^{

                                if (status)
                                {
                                    resultText = @"Operation completed. Would you like to continue?";

                                }
                                else
                                {
                                    resultText = @" Operation failed. Would you still like to continue?";
                                }
                                UIAlertView *result = [UIAlertView alertViewWithTitle:nil message:resultText cancelButtonTitle:@"Cancel" otherButtonTitles:[NSArray arrayWithObjects:@"OK",nil] onDismiss:^(int buttonIndex)
                                                       {
                                                           NSLog(@"selected button index: %d",buttonIndex);
                                                           if (buttonIndex == 0)
                                                           {
                                                               continueSharing=YES;
                                                               [conditionLock unlock];
                                                               NSLog(@"We are continuing sharing :)");
                                                           }
                                                       }onCancel:^{
                                                           continueSharing=NO;
                                                            [conditionLock unlock];
                                                           NSLog(@"cancelled");
                                                       }]; [result show];

                            });
         }];
        });
    }


    //should continue only after earlier if block finishes, ie after getting the continueSharing value

    if (continueSharing)
    {
        [self performSomeAnotherAsynchronousOperation];
    }

}

2 ответа

Решение

Вместо использования блокировок (которые предназначены только для обеспечения одновременного доступа к какому-либо общему ресурсу) вы можете использовать семафоры (которые разработаны так, чтобы один поток мог ожидать сигнала от другого потока, который необходим здесь).

Итак, вы должны создать семафор:

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

Блоки завершения просмотра предупреждений будут сигнализировать этот семафор:

dispatch_semaphore_signal(semaphore);

И где вы хотите дождаться этого сигнала (до того, как performSomeAnotherAsynchronousOperation):

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

Я немного подправил ваш код, но, в частности, изменил его, чтобы он не блокировал основную очередь (чего вы никогда не хотите делать), убедившись, что dispatch_semaphore_wait делается в фоновой очереди. Также обратите внимание, что dispatch_semaphore_signal не внутри if заявление. Это привело к:

- (void)shareOperation
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __block BOOL continueSharing = NO;
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

        [self performSomeAsynchronousOperationWithCompletionBlock:^(NSError *tError, bool status){
            dispatch_async(dispatch_get_main_queue(),^{
                NSString *resultText;

                if (status)
                    resultText = @"Operation completed. Would you like to continue?";
                else
                    resultText = @"Operation failed. Would you still like to continue?";

                UIAlertView *alertView = [UIAlertView alertViewWithTitle:nil message:resultText cancelButtonTitle:@"Cancel" otherButtonTitles:@[@"OK"] onDismiss:^(int buttonIndex) {
                    NSLog(@"selected button index: %d",buttonIndex);
                    if (buttonIndex == 0) {
                        continueSharing = YES;
                        NSLog(@"We are continuing sharing :)");
                    }
                    dispatch_semaphore_signal(semaphore);
                } onCancel:^{
                    dispatch_semaphore_signal(semaphore);
                    NSLog(@"cancelled");
                }];

                [alertView show];
            });
        }];

        // should continue only after earlier if block finishes, ie after getting the continueSharing value

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

        if (continueSharing)
            [self performSomeAnotherAsynchronousOperation];
    });
}

Более того, вам не следует использовать какой-либо механизм блокировки, такой как семафоры (конечно, не в главной очереди), а просто нужно иметь блок завершения для представления предупреждений, который сам инициирует следующий шаг процесса. Я понимаю, что вы говорите, что это не практично в вашем сценарии, но, как правило, это правильный способ справиться с этими сценариями.

Вы можете использовать блок задержки

 dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 0.01 * NSEC_PER_SEC);

    dispatch_after(delayTime, dispatch_get_main_queue(), ^(void){

    })
Другие вопросы по тегам