以下用于从主线程调用[self goToNext]的代码具有与用于< 1>的不同dispatch_xxxx不同的结果。和< 2>。
dispatch_async& dispatch_sync,结果为NULL。
- (NSString *)someString {
__block NSString *localSomeString;
dispatch_async(self.serialQueue, ^{ // dispatch_xxx <1>
if ([NSThread isMainThread]) {
NSLog(@"main thread");
} else {
NSLog(@"background thread");
}
localSomeString = @"fuck you!";
});
return localSomeString;
}
- (void)goToNext
{
dispatch_sync(self.serialQueue, ^{ // dispatch_xxx <2>
if ([NSThread isMainThread]) {
NSLog(@"main thread");
} else {
NSLog(@"background thread");
}
NSLog(@"%@", [self someString]);
});
}
有人可以解释四个结果的原因吗?
答案 0 :(得分:1)
首先:您应该(重新?)阅读GCD简介。在运行之前尝试一些选项是 no 选项 - 你显然做了什么 - ,因为这可能会在下一台机器上失败。
您创建一个串行队列。在串行队列中,一个块相继执行。这描述了下标彼此的关系,而不是调用者。
同步或异步订阅描述了块和订阅块的代码之间的关系。这不描述了彼此之间关系的关系,而是与&#34;调用者的关系&#34;:完全不同的东西。
下一步:测试线程毫无意义。队列可以更改它使用的线程。这就是它们的用途。
致你的问:
如果您将一个块订阅到串行队列中的串行队列,则内部队列必须等待外部队列完成,因为它是一个串行队列。这就是串行队列的本质。如果您使用dispatch_sync()
执行此操作,则调用者将等待,直到块完成。因此永远不会完成:死锁。我们的代码有一个简化版本:
dispatch_sync(self.serialQueue, // the caller waits for the code to be completed
^{
…
dispatch_sync(self.serialQueue, // the outer block waits for the code to be completed
^{
… // this code runs, after the outer block is completed.
});
…
});
内部块无法完成,因为它必须在外部块完成之前等待(串行队列)。外部块无法完成,因为它等待内部块完成(同步)。死锁:两人都在等待对方完成。
您想要完全不同的东西:您想要使用块的结果。只需在完成处理程序中传递处理结果的代码。然后,您可以使用完成处理程序中的结果立即返回:
- (void)someStringWithCompletionHandler:(void(^)(NSString *result))handler // No return type, but a completion handler
{
__block NSString *localSomeString;
dispatch_async(self.serialQueue,
^{
if ([NSThread isMainThread]) {
NSLog(@"main thread");
} else {
NSLog(@"background thread");
}
localSomeString = @"fuck you!";
handler( localSomeString );
});
}
然后这样称呼:
- (void)goToNext
{
dispatch_async(self.serialQueue,
^{
[self someStringWithCompletionHandler:
^(NSSTring *result)
{
NSLog( @"%@", result );
}]);
});
}
输入Safari。
BTW:在代码中用注释标记点,而不是使用内联标记。否则,没有人可以复制并粘贴代码并让它运行。
答案 1 :(得分:0)
在处理给定的代码块之前,对dispatch_async
的调用立即返回。因此,在异步示例中,localSomeString
在初始化之前返回(NULL
)。你可以通过引入一个完成块作为方法someString
的参数来解决这个问题,你可以在你的代码块中调用它:
- (void)someStringWithCompletion:(void(^)(NSString* someString))completion {
dispatch_sync<2>(self.serialQueue, ^{
if ([NSThread isMainThread]) {
NSLog(@"main thread");
} else {
NSLog(@"background thread");
}
localSomeString = @"fuck you to!";
completion(localSomeString)
});
}
- (void)goToNext
{
dispatch_sync<2>(self.serialQueue, ^{
if ([NSThread isMainThread]) {
NSLog(@"main thread");
} else {
NSLog(@"background thread");
}
[self someStringWithCompletion:^(NSString *result) {
NSLog(result);
}
});
}
对dispatch_sync
的调用将等待,直到处理完代码块,从而阻止调用它的线程。因此,如果您在当前使用的队列上调用dispatch_sync
,则当前使用的队列将一直等到代码块完成,但代码块永远不会执行,因为它位于相同(当前正在等待)的队列中。