本文共 8747 字,大约阅读时间需要 29 分钟。
深入浅出 Cocoa 多线程编程之 block 与 dispatch quene
深入浅出
Cocoa 多线程编程之 block 与 dispatch quene
罗朝辉(
CC 许可,转载请注明出处
block 是 Apple 在 GCC 4.2 中扩充的新语法特性,其目的是支持多核并行编程。我们可以将 dispatch_queue 与 block 结合起来 使用,方便进行多线程编程。
本文源 代码 下载:点击下载
1,实验工程准备
在 XCode 4.0 中,我们建立一个 Mac OS X Application 类型的 Command Line Tool,在 Type 里面我们选择 Foundation 就好,工程名字暂且为 StudyBlocks.默认生成的工程代码 main.m 内容如下:
int main (int argc, c*****t char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// insert code here
NSLog(@"Hello, World!");
[pool drain];
return 0;
}
2,如何编写 block
在自动生成的工程代码中,默认打印一条语句"Hello, World!",这个任务可以不可以用 block 语法来实现呢?答案是肯定的,请看:
void (^aBlock)(void) = ^(void){ NSLog(@"Hello, World!"); };
aBlock();
用上面的这两行语句替换 main.m 中的 NSLog(@"Hello, World!"); 语句,编译运行,结果是一样的。
这两行语句是什么意思呢?首先,等号左边的 void (^aBlock)(void) 表示声明了一个 block,这个 block 不带参数(void)且也无返回参数(void);等号右边的 ^(void){ } 结构表示一个 block 的实现体,至于这个 block 具体要做的事情就都在 {} 之间了。在这里我们仅仅是打印一条语句。整个语句就是声明一个 block,并对其赋值。第二个语句就是调用这个 block 做实际的事情,就像我们调用函数一样。block 很有点像 C++0X 中的 Lambda 表达式。
我们也可以这么写:
void (^aBlock)(void) = 0;
aBlock = ^(void) {
NSLog(@"Hello, World!");
};
aBlock();
现在我们知道了一个 block 该如何编写了,那么 block 数组呢?也很简单,请看:
void (^blocks[2])(void) = {
^(void){ NSLog(@" >> This is block 1!"); },
^(void){ NSLog(@" >> This is block 2!"); }
};
blocks[0]();
blocks[1]();
谨记!
block 是分配在 stack 上的,这意味着我们必须小心里处理 block 的生命周期。
比如如下的做法是不对的,因为 stack 分配的 block 在 if 或 else 内是有效的,但是到大括号 } 退出时就可能无效了:
dispatch_block_t block;
if (x) {
block = ^{ printf("true\n"); };
} else {
block = ^{ printf("false\n"); };
}
block();
上面的代码就相当于下面这样的 unsafe 代码:
if (x) {
struct Block __tmp_1 = ; // setup details
block = &__tmp_1;
} else {
struct Block __tmp_2 = ; // setup details
block = &__tmp_2;
}
3,如何在 block 中修改外部变量
考虑到 block 的目的是为了支持并行编程,对于普通的 local 变量,我们就不能在 block 里面随意修改(原因很简单,block 可以被多个线程并行运行,会有 问题的),而且如果你在 block 中修改普通的 local 变量,编译器也会报错。那么该如何修改外部变量呢?有两种办法,第一种是可以修改 static 全局变量;第二种是可以修改用新关键字 __block 修饰的变量。请看:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
__block int blockLocal = 100;
static int staticLocal = 100;
void (^aBlock)(void) = ^(void){
NSLog(@" >> Sum: %d\n", global + staticLocal);
global++;
blockLocal++;
staticLocal++;
};
aBlock();
NSLog(@"After modified, global: %d, block local: %d, static local: %d\n", global, blockLocal, staticLocal);
[pool drain];
执行之后,值均为:101
相似的情况,我们也可以引用 static block 或 __block block。比如我们可以用他们来实现 block 递归:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];