如何包装一个异步方法,该方法接受一个块并在目标c中将其转换为同步

kaw*_*vin 12 multithreading asynchronous objective-c grand-central-dispatch ios

我想包装一个如下所示的异步API:

[someObject completeTaskWithCompletionHandler:^(NSString *result) {

}];
Run Code Online (Sandbox Code Playgroud)

进入一个我可以像这样调用的同步方法

NSString *result = [someObject completeTaskSynchronously];
Run Code Online (Sandbox Code Playgroud)

我该怎么做呢?我做了一些文档阅读和谷歌搜索,并尝试使用"dispatch_semaphore"尝试实现它,如下所示:

-(NSString *) completeTaskSynchronously {
   __block NSString *returnResult;
   self.semaphore = dispatch_semaphore_create(0);  
   [self completeTaskWithCompletionHandler:^(NSString *result) {
       resultResult = result;
       dispatch_semaphore_signal(self.semaphore);
   }];

   dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
   return resultResult;
}
Run Code Online (Sandbox Code Playgroud)

但这似乎没有用,它基本上只是停在dispatch_semaphore_wait.执行永远不会到达执行_signal的内部块.任何人都有关于如何做到这一点的代码示例?我怀疑该块必须在主线程的其他线程上?此外,假设我无法访问异步方法背后的源代码.谢谢!

Jan*_*ano 9

dispatch_semaphore_wait阻止示例中的主队列.您可以将异步任务分派到不同的队列:

__block NSString *returnResult;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0UL);
dispatch_async(queue,^{
     result = [someObject completeTaskSynchronously];
});
Run Code Online (Sandbox Code Playgroud)

或者使用其他系统,如NSRunLoop:

   __block finished = NO;
   [self completeTaskWithCompletionHandler:^(NSString *result) {
       resultResult = result;
       finished = YES;
   }];
    while (!finished) {
        // wait 1 second for the task to finish (you are wasting time waiting here)
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]];
    }
Run Code Online (Sandbox Code Playgroud)


ork*_*den 6

使用NSRunLoop是最容易做到的.

__block NSString* result = nil;
[self completeTaskWithCompletionHandler:^(NSString *resultstring) {
    result = resultstring;
}];
while (!result) {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
Run Code Online (Sandbox Code Playgroud)

  • 这不能很好地工作.运行循环需要处理事件才能返回.如果没有事件,它将只返回"遥远的未来",即*永远不会*.此外,对指针`result`的访问不是线程安全的.不保证指针不为零并完全初始化.并且(可能)可以允许编译器优化对存储器位置的访问并将指针保持在永远不会更新的寄存器中. (3认同)

Mor*_*ion -3

您可以尝试使用 NSOperations 来异步执行您的操作。