繁体   English   中英

如何包装一个异步方法,该方法接受一个块并将其在 Objective-C 中同步

[英]How to wrap an asynchronous method that takes a block and turn it synchronous in Objective-C

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

[someObject completeTaskWithCompletionHandler:^(NSString *result) {

}];

进入我可以这样调用的同步方法:

NSString *result = [someObject completeTaskSynchronously];

我该怎么做? 我做了一些文档阅读和互联网搜索,并尝试使用“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 的块内。 任何人都有关于如何做到这一点的代码示例? 我怀疑该块必须位于主线程之外的不同线程上? 另外,假设我无权访问异步方法背后的源代码。

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];
});

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

我认为更好的解决方案是 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 来异步执行您的操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM