iOS - Block -内存1

2017-01-14 10:20:45来源:http://www.jianshu.com/p/57b6139b46c8作者:学习路上一个远行者人点击

Block对外部变量的引用

1.所有人都只知道在不考虑 __block情况下,block对外部变量的会进行copy,在iOS copy分为mutableCopycopy,那么block copy是哪一种呢?一个很常见的例子:


    int a= 1;
int b = 2;
int (^sum)(void) = ^(void) {
return a * b;
};
NSLog(@"%d", sum()); // 3
a = 5;
b = 6;
NSLog(@"%d", sum()); //3

我想大家对这对代码的结果很清楚,根据两次相同的结果我们知道suma ,b进行了copy,而这种copy应该是mutableCopy,重新开辟了一段内存空间来存储a,b
接下来一个非常相似的代码:


    Person *p = [[Person alloc]init];
p.name = @"yan";
void (^test)(void) = ^() {
p.name = @"zhao";
NSLog(@"%@", p);
};
test();
NSLog(@"%@", p.name);

我想大家一定不会觉得输出来的还是yan, 凭直觉应该是zhao。答案就是zhao。大家可以自己做一个小程序试试,对比这个两个我们应该会发现一些问题,为什么对于基本类型(int float double)输出的结果不影响,但是对于OC 对象就影响呢。答案就是ab 进行的是深复制,而对象p 进行的浅复制。
总结:block对基本类型进行的是深复制,但是对OC对象(没有被__block修饰)进行的是浅复制,只是增加OC对象的retainCount。


2.继续第一步,我们是在没有__block修饰的情况下进行的。如果我没有__block进行修饰,那么在block中没有权利进行修改(这里的修改是指指针的变动,而不是某个对象属性的改变),当我们加上__block修饰符的时候,block不会对对象进行复制。也就是说block不会拥有引用的外部OC对象,代码里子:


    Person *p = [[Person alloc]init]; // retainCount = 1
p.name = @"yan";
void (^test)(void) = ^() {
p.name = @"zhao"; // retainCount = 3
NSLog(@"%@", p);
};
test();
NSLog(@"%@", p.name); // retainCount = 3

    __block Person *p = [[Person alloc]init]; // retainCount = 1
p.name = @"yan";
void (^test)(void) = ^() {
p.name = @"zhao"; // retainCount = 1
NSLog(@"%@", p);
};
test();
NSLog(@"%@", p.name); // retainCount = 1

根据代码可以发现,p的retainCount没有增加--- 题外话:怎么在ARC下查看retainCount: CFGetRetainCount((__bridge CFTypeRef)(p))
这时候我们可以引入出来另外一个话题就是block的循环引用


3.block循环引用
block会对外部的变量进行复制(也就是强引用),当我们在block中使用 实例变量, 发送消息。block都会对self进行强引用。这样很容易形成retain cycle。那么应该怎么样进行解决呢。我在这里总结一下:


__weak __typeof(self) weakSelf = self;
void (^test)(void) = ^() {
if (!weakSelf) return;
weakSelf.name = @"zhao";
};

__weak __typeof(self) weakSelf = self;
void (^test)(void) = ^() {
__Strong __typeof(weakSelf) strongSelf = weakSelf;
strongSelf.name = @"zhao";
};

前面这两种是非常常见得。而且也是比较正规的。if (!weakSelf) return; __Strong __typeof(weakSelf) strongSelf = weakSelf; 都是为了防止selfnil


__block Viewcontoller *vc = self;
void (^test)(void) = ^() {
vc.name = @"zhao";
};

4.block的分类


NSGlobalBlock: 没有引入外部变量
NSStackBlock:在MRC下,引用了外部变量是放在栈上的。在ARC应该用__weak 修饰
NSMallocBlock:在MRC下需要进行Block_copy,在ARC只要有强指针指向就可以放在堆上。
如果block 是 Stack:
  Person *p = [[Person alloc]init]; // retainCount = 1
p.name = @"yan";
void (^test)(void) = ^() {
p.name = @"zhao"; // retainCount = 2
NSLog(@"%@", p);
};
test();
NSLog(@"%@", p.name); // retainCount = 2

与原来相比对P的retainCount的操作只增加1,而不是2.
5.问题
strong block为什么对对象的进行复制时,对象的retaincount直接增加2.而weak block 只增加 1? 希望大家可以指教一二。



最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台