gpt4 book ai didi

ios - 如何等待具有完成 block 的方法(全部在主线程上)?

转载 作者:IT王子 更新时间:2023-10-29 08:11:02 25 4
gpt4 key购买 nike

我有以下(伪)代码:

- (void)testAbc
{
[someThing retrieve:@"foo" completion:^
{
NSArray* names = @[@"John", @"Mary", @"Peter", @"Madalena"];
for (NSString name in names)
{
[someObject lookupName:name completion:^(NSString* urlString)
{
// A. Something that takes a few seconds to complete.
}];

// B. Need to wait here until A is completed.
}
}];

// C. Need to wait here until all iterations above have finished.
STAssertTrue(...);
}

这段代码在主线程上运行,完成 block A也在主线程上。

  • 我如何在 B 处等待 A 完成?
  • 随后如何在 C 处等待外部完成 block 完成?

最佳答案

如果您的完成 block 也在主线程上调用,则可能很难实现这一点,因为在完成 block 执行之前,您的方法需要返回。您应该将异步方法的实现更改为:

  1. 保持同步。
  2. 使用其他线程/队列完成。然后你可以使用 Dispatch Semaphores 来等待。您用值 0 初始化一个信号量,然后在主线程上调用 wait 并在完成时调用 signal

无论如何,在 GUI 应用程序中阻塞主线程是一个非常糟糕的主意,但这不是您问题的一部分。在测试、命令行工具或其他特殊情况下可能需要阻塞主线程。在这种情况下,请进一步阅读:


如何在主线程上等待主线程回调:

有一种方法可以做到,但可能会产生意想不到的后果。 谨慎行事!

主线程是特殊的。它运行 +[NSRunLoop mainRunLoop],它还处理 +[NSOperationQueue mainQueue]dispatch_get_main_queue()。分派(dispatch)到这些队列的所有操作或 block 都将在主运行循环中执行。这意味着,这些方法可以采用任何方法来安排完成 block ,这应该适用于所有这些情况。在这里:

__block BOOL isRunLoopNested = NO;
__block BOOL isOperationCompleted = NO;
NSLog(@"Start");
[self performOperationWithCompletionOnMainQueue:^{
NSLog(@"Completed!");
isOperationCompleted = YES;
if (isRunLoopNested) {
CFRunLoopStop(CFRunLoopGetCurrent()); // CFRunLoopRun() returns
}
}];
if ( ! isOperationCompleted) {
isRunLoopNested = YES;
NSLog(@"Waiting...");
CFRunLoopRun(); // Magic!
isRunLoopNested = NO;
}
NSLog(@"Continue");

这两个 bool 值是为了在 block 立即同步完成的情况下确保一致性。

如果 -performOperationWithCompletionOnMainQueue:异步,输出将是:

Start
Waiting...
Completed!
Continue

如果方法是同步,输出将是:

Start
Completed!
Continue

什么是魔法?调用 CFRunLoopRun() 不会立即返回,只有在调用 CFRunLoopStop() 时才会返回。此代码主运行循环上,因此再次运行主运行循环将恢复执行所有计划 block 、计时器、套接字等。

警告:可能的问题是,所有其他预定的计时器和 block 将同时执行。此外,如果从未调用完成 block ,您的代码将永远不会到达 Continue 日志。

您可以将此逻辑包装在一个对象中,这样可以更轻松地重复使用此模式:

@interface MYRunLoopSemaphore : NSObject

- (BOOL)wait;
- (BOOL)signal;

@end

所以代码将被简化为:

MYRunLoopSemaphore *semaphore = [MYRunLoopSemaphore new];
[self performOperationWithCompletionOnMainQueue:^{
[semaphore signal];
}];
[semaphore wait];

关于ios - 如何等待具有完成 block 的方法(全部在主线程上)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17920169/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com