如何在 GCD 块中返回当前方法



这是我的代码:

- (void)viewDidLoad {
[super viewDidLoad];
[self testGCD];
}
- (void)testGCD {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"1");
return;
});
NSLog(@"2");
}

控制台打印了 12。

我想要的只是第一次打印 1。我认为也许return不是从方法返回,而是从块返回。

有什么方法可以从此 GCD 块中的当前方法返回?

使用块来解决问题。

- (void)testGCD {
__block void(^codeBlock)(void) = ^{ NSLog(@"2"); };
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
codeBlock = ^{ NSLog(@"1"); };
});
codeBlock();
}

如果您看到dispatch_once的定义,那么您会看到他们正在使用DISPATCH_EXPECT来比较onceToken。您也可以使用if (onceToken != -1)DISPATCH_EXPECT通过告诉编译器onceToken == -1概率要高得多来优化代码。这称为分支预测

- (void)testGCD {
static dispatch_once_t onceToken;
if (DISPATCH_EXPECT(onceToken, ~0l) != ~0l) {
dispatch_once(&onceToken, ^{
NSLog(@"1");
return;
});
}
else {
NSLog(@"2");
}
}
- (void)testGCD {
static dispatch_once_t onceToken;
__block NSString *text = @"2";
dispatch_once(&onceToken, ^{
text = @"1";
});
NSLog(@"%@", text);
}

return语句从当前封闭作用域返回,在您的情况下是块。 不能从外部封闭范围返回。

可以使用简单的布尔标志来确定这是否是代码首次执行,并使用串行调度队列来确保它是线程安全的。

像这样:

- (void)testGCD {
static dispatch_queue_t queue = dispatch_queue_create("com.example.MyQueue", NULL);
static bool firstRun = YES;
dispatch_sync(queue, ^{
if (firstRun) {
NSLog(@"1);
firstRun = NO;
} else {
NSLog(@"2");
}
});
}

通过使用串行调度队列,可以确保不能同时更新firstRun

块就像一个完全独立的方法。其中的return只会从块中返回。您实际上似乎需要的是:

- (void)testGCD {
static BOOL didTrigger = NO;
if(didTrigger) {
NSLog(@"2");
}
else {
didTrigger = YES;
NSLog(@"1");
}
}

您可能会尝试在箱子中设置一个简单的锁,但我不确定在这种情况下它有多安全:

- (void)testGCD {
static dispatch_once_t onceToken;
static BOOL didInvokeOnceBlock = NO;
static BOOL didPassSkippedBlock = NO;
dispatch_once(&onceToken, ^{
NSLog(@"1");
didInvokeOnceBlock = YES;
});
if(didInvokeOnceBlock && didPassSkippedBlock) {
NSLog(@"2");
}
didPassSkippedBlock = YES;
}

但这看起来在多线程时可能会产生不稳定的结果。您可能需要以原子方式运行此操作才能使结果正确。我认为潜在的问题是:

  • 线程 A 和线程 B 开始执行相同的方法。
  • 线程 A 收集令牌并解锁didInvokeOnceBlock
  • 线程 B 跳过块并解锁didPassSkippedBlock但跳过NSLog(@"2");
  • 线程 A 调用NSLog(@"2");

最新更新