iOS 与前端iOS Developer程序员

iOS - Block -内存1

2016-11-02  本文已影响57人  学习路上一个远行者
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的分类

    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.问题

  1. strong block为什么对对象的进行复制时,对象的retaincount直接增加2.而weak block 只增加 1? 希望大家可以指教一二。
上一篇下一篇

猜你喜欢

热点阅读