事实证明,一点也不难。我试图用我的发现来更新这个,我会继续更新这个。
异步属性的 getter 应该如何表现?
Perform asynchronous request
如果属性不可用并且set the property
. (用于延迟加载)
- 可用时归还该财产。
挑战:
虽然,它可能会令人困惑,因为为什么不在这里使用同步方法?, 答案是它会冻结 UI。
没有人知道异步请求何时会完成,但这并不意味着对可用性状态的全部需求应该是未知的。从硬件、内核到更高级别的 API,所有系统中都有相应的机制。您可以将Protocols 和 Delegates作为传达此信息的一种方式。
为什么不将协议和委托用于异步属性?
- 我将不得不强制在所有引用类中实现委托 ->不是 getter。
- 我不希望其他类知道它是一个异步属性,如果他们想要数据,他们会在数据可用时得到它,而他们不知道如何检索它的性质。(obv 没有冻结 UI)。
我们如何在不使用协议和委托或将其转换为同步调用的情况下实现这一点?
答案是使用条件变量。请注意,此条件变量与我们用于分支的条件变量不同。它必须是线程安全的,并在编译器和内核级别得到支持。
- NS条件
从官方文档,
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 方法在不使用委托的情况下知道异步请求的完成。
-(NSMutableDictionary*) myDictionary {
if(!_myDictionary) {
_myDicitonary = [self someOtherMethod];
}
return _myDictionary;
}
虽然锁和异步请求可以在 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
它将禁止控制超出它。但实际上布尔谓词在保持锁定方面起着非常重要的作用,如文档中所述。
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.