如何return GCD 块中的当前方法?
How to return current method in GCD block?
这是我的代码:
- (void)viewDidLoad {
[super viewDidLoad];
[self testGCD];
}
- (void)testGCD {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"1");
return;
});
NSLog(@"2");
}
控制台打印出1和2.
我想要的只是第一次打印1。我想也许 return
不是 return 来自方法,而是来自块。
有什么方法可以return从这个 GCD 块中的当前方法?
来自当前封闭范围的 return
语句 returns,在您的例子中是块。您不能从外部封闭范围 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
只会 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");
- (void)testGCD {
static dispatch_once_t onceToken;
__block NSString *text = @"2";
dispatch_once(&onceToken, ^{
text = @"1";
});
NSLog(@"%@", text);
}
使用块来解决问题。
- (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)viewDidLoad {
[super viewDidLoad];
[self testGCD];
}
- (void)testGCD {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"1");
return;
});
NSLog(@"2");
}
控制台打印出1和2.
我想要的只是第一次打印1。我想也许 return
不是 return 来自方法,而是来自块。
有什么方法可以return从这个 GCD 块中的当前方法?
来自当前封闭范围的 return
语句 returns,在您的例子中是块。您不能从外部封闭范围 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
只会 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");
- (void)testGCD {
static dispatch_once_t onceToken;
__block NSString *text = @"2";
dispatch_once(&onceToken, ^{
text = @"1";
});
NSLog(@"%@", text);
}
使用块来解决问题。
- (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");
}
}