如何包装一个asynchronous方法,它将一个块转换为同步的目标c

我想包装一个看起来像这样的asynchronousAPI:

[someObject completeTaskWithCompletionHandler:^(NSString *result) { }]; 

转换成我可以这样调用的同步方法

 NSString *result = [someObject completeTaskSynchronously]; 

我该怎么做呢? 我做了一些文档阅读和谷歌search,并尝试使用“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; } 

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

dispatch_semaphore_wait在你的例子中阻塞主队列。 您可以将asynchronous任务分派到不同的队列中:

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

或者使用一些其他的系统,比如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]]; } 

使用NSRunLoop在这里最容易做到。

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

我认为更好的解决scheme将如下所示NSRunLoop。 它简单,工作正常。

 - (NSString *)getValue { __block BOOL _completed = NO; __block NSString *mValue = nil; [self doSomethingWithCompletionHandler:^(id __nullable value, NSError * __nullable error) { mValue = value; _completed = YES; }]; while (!_completed) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; } return mValue; } 

你可以尝试使用NSOperations来做这个asynchronous的事情。