Tho*_*cic 2 objective-c objective-c-blocks dispatch-async
我在使用GCD的Objective-C中遇到以下问题我无法弄清楚:
我使用以下方法计算一些648个瓷砖的东西.首先处理瓦片的顺序由设置变量"pi"的一些算法给出.变量"loaded"在此上下文中是全局变量,从0开始并正确地上升到647.
不使用块时,一切都很完美.
while (loaded < [self.tiles count]) {
long pi = /* tricky way to calculate the position index to set */;
NSLog(@"loaded: %d", loaded);
// Do this in a separate thread
dispatch_async(loader, ^{
NSLog(@"loaded ->: %d", loaded);
[self.tiles[loaded] setPositionIndexTo:pi];
});
loaded++;
}
Run Code Online (Sandbox Code Playgroud)
问题:
我得到一个例外,因为该块试图访问self.tiles [648]!在Apple的块文档中,可以看出,在创建块时,块中的变量值被捕获,所以我不明白,这是怎么回事.我确实理解加载的变量实际上最终确实具有值648,这应该在不执行的情况下中止循环.其他一些奇怪的是,值0也从未在块中使用,但它从1开始.有时也可能看到块在有关加载值的循环之前,有时会错过值,或做两次.这是一些输出:
loaded ->: 612
loaded: 613
loaded ->: 613
loaded ->: 614
loaded: 614
loaded ->: 614
loaded: 615
loaded: 616
loaded ->: 615
loaded: 617
loaded ->: 617
Run Code Online (Sandbox Code Playgroud)
为什么以及如何实现这一目标?
感谢任何澄清,正如我认为Apple的文档明确指出的那样,当创建块时,应该捕获"已加载"的值而不再对块进行更改.
问题是它loaded是一个实例变量,而不是局部变量.块捕获本地范围.在Objective-C中,当您访问实例变量时,编译器会将该访问权转换为结构成员访问权.
@interface MyClass : NSObject
{
int varA;
}
@end
@implementation MyClass
- (void)someMethod
{
varA = 42; // This
self->varA = 42 // is actually this after compilation
}
@end
Run Code Online (Sandbox Code Playgroud)
因此,该块将始终在运行时看到加载的当前值,因为它实际上正在查看self->loaded.
这个问题有多种解决方案,但一般来说,您需要确保每个块都看到一个唯一的值loaded.一个简单的方法是创建loaded一个局部变量.如果需要跟踪整体进度,请从块中更新进度属性.(请注意,如果loader是并发队列,则在更新progress属性时需要注意多线程问题.一个简单的解决方案是将更新分发回自定义串行队列.)
| 归档时间: |
|
| 查看次数: |
957 次 |
| 最近记录: |