void test1() {
int a = 10;
void (^block)(void) = ^{
NSLog(@"a is %d", a);
};
a = 20;
block();//10
}
void test2() {
__block int a = 10;
void (^block)(void) = ^{
NSLog(@"a is %d", a);
};
a = 20;
block();//20
}
void test3() {
static int a = 10;
void (^block)(void) = ^{
NSLog(@"a is %d", a);
};
a = 20;
block();//20
}
int a = 10;
void test4() {
void (^block)(void) = ^{
NSLog(@"a is %d", a);
};
a = 20;
block();//20
}
造成这样的原因是:传值和传址。
使用clang命令可以将代码编译成C++:
void test1() {
int a = 10;
void (*block)(void) = ((void (*)())&__test1_block_impl_0((void *)__test1_block_func_0, &__test1_block_desc_0_DATA, a));
a = 20;
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
void test2() {
attribute((blocks(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 10};
void (*block)(void) = ((void (*)())&__test2_block_impl_0((void *)__test2_block_func_0, &__test2_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
(a.__forwarding->a) = 20;
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
void test3() {
static int a = 10;
void (*block)(void) = ((void (*)())&__test3_block_impl_0((void *)__test3_block_func_0, &__test3_block_desc_0_DATA, &a));
a = 20;
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
void test4() {
void (block)(void) = ((void ()())&__test4_block_impl_0((void *)__test4_block_func_0, &__test4_block_desc_0_DATA));
a = 20;
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
总结:只有普通局部变量是传值,其他情况都是传址。
3、block的内存管理
- 无论当前环境是ARC还是MRC,只要block没有访问外部变量,block始终在全局区
2.MRC情况下,
block如果访问外部变量,block在栈里
不能对block使用retain,否则不能保存在堆里
只有使用copy才能放到堆里
3.ARC情况下
block如果访问外部变量,block在堆里
block可以使用copy和strong,并且block是一个对象
4、block的循环引用
如果要在block中直接使用外部强指针会发生错误,使用以下代码在block外部实现可以解决
__weak typeof(self) weakSelf = self;
但是如果在block内部使用延时操作还是用弱指针的话回去不到该弱指针,需要在block内部再将弱指针强引用以下
__strong typeof(self) strongSelf = weakSelf;
5、block中的weak self,是任何时候都需要加的么?
不是什么任何时候都需要加的,不过任何时候都添加似乎总是好的。只要出现像self->block->self.property/self->Ivar这样的结构连时,才会出现循环引用问题。
6、block的变量传递
如果block访问的外部变量是局部变量,那么就是值传递,外界改了,不会影响里面
如果block访问的外部变量是__block或者static修饰,或者是全局变量,那么就是指针传递,block里面的值和外界同一个变量,外界改变,里面也会改变
验证一下是不是这样
通过Clang来将main.m文件编译成C++
在终端输入如下命令clang -rewrite-objc main.m
void(block)() = ((void ()())&__main_block_impl_0((void )__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 )&a, 570425344));
void(block)() = ((void ()())&__main_block_impl_0((void *)__main_block_func_0,
可以看到在编译后的代码最后可以发现被__block修饰过的变量使用的是&a,而局部变量是a
7、block的注意点
在block内部使用外部指针且会造成循环引用情况下,需要用__weak修饰外部指针
__weak typeof(self) weakSelf = self;
在block内部如果使用了延时函数还是用弱指针会取不到该指针,因为已经被销毁了,需要在block内部再将弱指针重新强引用一下
__strong typeof(self) strongSelf = weakSelf;
如果需要在block内部改变外部变量的话,需要在用__block修饰外部变量
网友评论