如何从asynchronous属性的getter返回?

我已经覆盖了一个请求在线服务获取结果的getter。 如何强制getter只返回来自同步块的结果?

@interface MyClass () @property (nonatomic, strong) NSMutableDictionary* myDictionary; @end @implementation MyClass -(NSMutableDictionary*) myDictionary { dispatch_async(queue, ^{ /* perform online request */ dispatch_sync(dispatch_get_main_queue(), ^{ // I need to obtain lock until this line gets executed and only then return }); }); } @end 

用相当不错的谷歌search至less3小时,我遇到了dispatch_group_asyncdispatch_semaphore__block 。 我不知道我是否用错了,但没有达到目的。

更新1:

myDictionary是一个asynchronous属性。 我想看看是否可以通过getter本身来实现。

@Kishor当请求是真正asynchronous的时候,UI不会被阻塞。 你的“asynchronous”请求阻塞UI的原因是,事实上它们不是不同步的。 这是为什么在伪代码:

 - (double) notTruelyAsyncValue { __block double someExpensiveDoubleToCompute = 0.0; // One of the many ways that we can coordinate concurrent threads. dispatch_semaphore_t sema_done = dispatch_semaphore_create(0); dispatch_async(not_the_main_queue, ^(void) { // Simulate long processing time. sleep(5); someExpensiveDoubleToCompute = 3.1415926535; dispatch_semaphore_signal(sema_done); }); // We can't return until the async block has returned. // So we wait until it's done. If we wait on the main queue // then our UI will be "frozen". dispatch_semaphore_wait(sema_done, DISPATCH_TIME_FOREVER); // Now we have our result we free the resources and return dispatch_release(sema_done); return someExpensiveDoubleToCompute; } 

如果你从一个asynchronous线程调用这个方法,它将不会阻塞UI,但是如果你从主队列/线程调用它,那么它会阻塞UI,因为你正在等待主线程上的信号量。 不pipe你如何实现你的等待,它总是会阻塞UI,因为主线程是一个串行队列。 这意味着在完成asynchronous块之前,主队列上的其他块或事件将不会运行。

如果你不想阻塞你的UI,那么不要调用任何可能会阻塞主线程的东西。 一个好的模式是使用@Collinbuild议的完成块。 模式如下:

 - (void) computeAnyncValueWithCompletionBlock:((void)^(double value))completionBlock { dispatch_async(not_the_main_queue, ^(void) { // do some expensive computation. double value = 3.1415926535; completionBlock(value); }); } 

这可以从任何地方调用,永远不会阻止。

纠正我,如果我不清楚 – 它听起来像你想要做的是在后台下载,而也从非方式返回的方法? 如果你考虑这个问题,你就试图同时做两个矛盾的事情:方法要么阻塞,要么直到返回或者asynchronous返回。

我想你想要的是一个完成块 。 而不是重写myDictionary ,你可以创build另一个方法来做这样的事情:

 - (void)downloadWithCompletion:(void(^)(NSDictionary *dictionary))completion { dispatch_async(queue, ^{ /* perform online request */ // Create an NSDictionary from what was downloaded. NSDictionary *dictionary = <parsed request data> dispatch_sync(dispatch_get_main_queue(), ^{ // Call the completion block using the info that was downloaded // where self.myDictionary could be set. completion(dictionary); }); }); } 

事实certificate,并不困难。 我试图用我的发现来更新这个,我会继续更新这个。

asynchronous属性的getter应该如何工作?

  1. 如果属性不可用,则Perform asynchronous requestset the property 。 (对于懒加载)
  2. 当可用时返回属性。

挑战:

  • UI冻结
  • 无效的回报

虽然, 为什么不在这里使用同步方法呢? ,答案是会冻结用户界面。

没有人知道何时完成asynchronous请求,但这并不意味着对可用性状态的整体需求应该是未知的。 从硬件,内核到更高级别的API都有这样的机制。 您可以参考协议和代表作为沟通的手段之一。


为什么不使用协议和委托进行asynchronous属性?

  1. 我将不得不强制执行所有引用类中的委托 – > 不是一个getter
  2. 我不希望其他类知道它是一个asynchronous属性,如果他们想要的数据,他们会得到它时,可以不知道它是如何检索的本质。 (obv不冻结用户界面)。

我们如何在不使用协议和委托的情况下实现这一目标,或者将它变成同步呼叫?

答案是通过使用条件variables 。 请注意,这个条件variables与我们用于分支的不同。 它必须是线程安全的,并在编译器和内核级别上得到支持。

  1. NSCondition

从官方文件来看,

 The NSCondition class implements a condition variable whose semantics follow those used for POSIX-style conditions. A condition object acts as both a lock and a checkpoint in a given thread. The lock protects your code while it tests the condition and performs the task triggered by the condition. The checkpoint behavior requires that the condition be true before the thread proceeds with its task. While the condition is not true, the thread blocks. It remains blocked until another thread signals the condition object. 

我所要做的就是让这个getter方法知道asynchronous请求完成而不使用委托。

 -(NSMutableDictionary*) myDictionary { if(!_myDictionary) { _myDicitonary = [self someOtherMethod]; } return _myDictionary; } 

虽然锁和asynchronous请求可以在getter本身中实现,但我拒绝这样做,以便于操作锁。 此外,这是一个很好的逻辑分离:)

 - (NSMutableDictionary *)someOtherMethod { NSCondition *lockForCompletion = [[NSCondition alloc] init]; __block BOOL available = NO; __block NSMutableDictionary* tempDict = [[NSMutableDictionary alloc] init]; [lockForCompletion lock]; // acquire the lock dispatch_async(queue, ^{ /* perform online request */ dispatch_sync(dispatch_get_main_queue(), ^{ [tempDict setObject:myResponse forKey:@"mykey" count:1]; available = YES; [lockForCompletion signal]; }); }); while(!available) { [lockForCompletion wait]; } [lockForCompletion unlock]; return tempDict; } 

我还想指出,最初available的布尔谓词并不是必须的,因为wait将禁止控制超出它。 但实际上,布尔谓词在保持locking状态方面起着非常重要的作用,如文档中所述。

 A boolean predicate is an important part of the semantics of using conditions because of the way signaling works. Signaling a condition does not guarantee that the condition itself is true. There are timing issues involved in signaling that may cause false signals to appear. Using a predicate ensures that these spurious signals do not cause you to perform work before it is safe to do so. The predicate itself is simply a flag or other variable in your code that you test in order to acquire a Boolean result.