Как заставить определенную часть функции ждать в 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){
})