三大类型
NSGlobalBlock: 位于内存静态全局区。没有调用任何变量或者调用的为全局变量、静态变量。你可以理解为声明的时候,加了static关键字
static NSString *test = @"test";
//前面可加static修辞
dispatch_block_t block = ^{
NSString *t = test;
};
NSLog(@"%@", block);
NSLog(@"%@", ^{
NSString *t = test;
});
注意:这里打印分为通过变量赋值打印和直接打印,NSGlobalBlock是没有区别的,为何会区分,后面NSMallocBlock会说。
你可以在dispatch_block_t前也加上static关键字,表明类型,是静态全局的block,即NSGlobalBlock,不会有任何问题
NSStackBlock:内部引用的为非全局、静态区的变量,初始则为NSStackBlock
NSString *test = @"test";
NSLog(@"%@", ^{
NSString *t = test;
});
注意:这里并不是采用通过一个变量赋值block再打印该变量的方式来确认类型,而是直接打印,区别在NSMallocBlock会提到
这里可以理解为
^{
NSString *t = test;
}
它其实就是一个局部变量,可以看做整个就是一个比如变量b,而局部变量是在栈中,因此打印出的类型是NSStackBlock
NSMallocBlock:由NSStackBlock类型的block通过copy后拷贝到堆中的block
NSString *test = @"test";
dispatch_block_t b = ^{
NSString *t = test;
};
NSLog(@"%@", b);
NSLog(@"%@", [^{
NSString *t = test;
} copy]);
block初始非NSGlobalBlock即NSStackBlock,只有经过copy后才会变为NSMallocBlock,上述代码中:
dispatch_block_t b = ^{
NSString *t = test;
};
这里的变量b并不是初始化,右边才是,block作为oc对象,内部经过了优化,可以理解为它在等号右边的时候,若block类型为NSStackBlock,左边的变量赋值时会copy该block到堆,上述代码中,右边的
^{NSString *t = test}
作为局部变量,为NSStackBlock,左边的b在本次赋值的时候copy了右边的block到堆,成为NSMallocBlock
这里在dispatch_block_t前面加上static,你会发现会报错:
Error:(28, 33) initializer element is not a compile-time constant
加static,即表明你要申明的是一个静态的block类型,即NSGlobalBlock类型,而ARC优化后,变量通过等号赋值block,会将block拷贝到堆,变成NSMallocBlock,类型不符,自然会报错。
这个错误你通过类似
static UIView *model = [[UIView alloc] init];
一样能得到,我们知道,对象通过alloc分配地址在堆,因此不能用static修辞后直接赋值
小结
单纯的block,要么为NSGlobalBlock类型,要么为NSStackBlock类型
static NSString *global = @"global";
//NSGlobalBlock类型
^{
NSString *g = global;
};
NSString *stack = @"stack";
//NSStackBlock类型
^{
NSString *s = stack;
};
NSStackBlock类型的block通过等号赋值或者copy方法后,新的block为NSMallocBlock类型
NSString *stack = @"stack";
//NSMallocBlock类型
dispatch_block_t block = ^{
NSString *s = stack;
};
//NSMallocBlock类型
[^{
NSString *s = stack;
} copy];
3.ARC中,block作为属性,基于历史原因,平常还是用copy修辞,实际上属性内部自动生成的setter方法其实也是通过等号将传入的block赋值给成员变量,既然通过等号赋值,那么该变成NSStackBlock的自然会变,即:
block作为属性,可以不用copy而用strong修辞,甚至两者都可以省略