美文网首页
读书笔记(二)

读书笔记(二)

作者: soundtravel | 来源:发表于2015-07-07 10:14 被阅读38次

    void (^blk) (void) = ^{pringf("block \n");};

    这个block的其实就是编译成一个函数指针void (*blk) (void) = &impl_0(func_0, &desc_0)

    impl_0 func_0 desc_0都是结构体,impl_0的构造函数是以func_0,desc_0型变量为参数的。

    blk(); 使用block其实就是调用函数指针,(*blk->impl.FuncPtr)(blk); (func_0以impl_0为参数)

    block如何截取局部变量的值的?

    在编译的时候,如果block声明前有局部变量,并在block内被使用了,在impl_0的构造函数的参数列表就有这个局部变量,并且使用局部变量的值来初始化;在impl_0的成员变量也添加了这些成员变量。

    在block声明前如果有静态局部变量,

    static int static_val = 3;

    相当于在impl_0内增加了int *static_val成员变量,使用该变量时即是使用它的指针进行访问。

    为什么非静态的局部变量没有用这个方式来进行访问呢,如果这样就不存在block截获局部变量的值的情况了。因为如果局部变量被截获后(在block声明处被截获),如果该局部变量作用域结束,这个局部变量就被废弃了,block中就不能再对它访问了。

    __block实现

    __block int val = 0;

    被编译成:(括号里面是赋的值)

    struct __Block_byref_val_0{

        void *__isa;(0)

        __Block_byref_val_0 * __forwarding;(&val)

        int __flags;(0)

        int __size;(__Block_byref_val_0)

        int val;(10)

    }

    block内对val赋值:

    ^{val = 1;}

    在func_0内被编译成,在impl_0中同样会添加成员变量

    {

        __Block_byref_val_0 *val = __cself->val;

        val->__forwarding->val = 1;

    }

    Block存储域

    一般block设置在上,_NSConcreteStackBlock。isa=_NSConcreteStackBlock

    有两种情况在global数据区 即isa=_NSConcreteGlobalBlock:

    1、block声明为全局变量

    2、block中不截获局部变量的值(执行时不依赖局部变量的值,整个程序只需一个实例)

    设置在栈上有个问题,就是声明block时的变量作用域结束了,栈也就没了,block和__block变量也都没了,所以arc时,大多数情况下编译器会自动生成将block从栈上复制到堆上的代码来解决这个问题。

    比如下面这个将block作为函数返回值

    blk_t func(int rate)

    {

        return ^(int count){return rate * count;};

    }

    blk_t func(int rate)

    {

        blk_t tmp = &_func_block_impl_0(func_0,desc_0,rate);

        tmp = _Block_copy(tmp);从栈复制到堆

        return objc_autoreleaseReturnValue(tmp); 注册到autoreleasePool并返回

    }

    有些情况编译器不能判断:

    函数参数传递block(例外:函数里面已经复制了参数的就不用在函数前手动复制了,还有框架的某个方法名中有usingBlock,GCD的API里)

    对block调用copy方法时,原来在栈上的block复制到堆上;原来在数据区的,什么也不做;原来在堆的,引用计数加1

    那么block中使用的__block变量在block从栈复制到堆上又发生了什么?

    同样是从栈复制到堆,并依然被该block所持有。

    __block变量在从栈复制到堆上的时候,将__forwarding指向堆上的__block变量,所以不论是访问栈上的(在block外使用__block变量)还是访问堆上的(block内使用__block变量),都能通过val.__forwarding->val来访问。(访问的都是堆上的??)

    block持有截获的局部变量(如果是weak类型呢??)

    typedef void(^blk_t)(id obj);

    blk_tblk;

    {

    id array = [[NSMutableArray alloc] init];

    blk = [^(id b){

    [array addObject:obj];

    NSLog(@"array count %ld",[array count]);

    }copy];

    }

    blk([[NSObject alloc] init]);

    blk([[NSObject alloc] init]);

    blk([[NSObject alloc] init]);

    strong

    block在编译后成员变量添加了id __strong array;

    由于[block copy]的调用,多了__main_block_copy_0和__main_block_dispose_0方法,在__main_block_copy方法中调用__Block_object_assign将对象赋值给array成员变量并持有该对象,同理,__main_block_dispose_0方法中调用_Block_object_dispose释放赋值给array的对象。

    所以在大括号结束时,即便array已经超过变量作用域,堆上的block依然持有该对象,不能被废弃。

    block从栈赋值到堆有四种情况:

    1、[block copy]

    2、return block; block作为函数返回值

    3、id strong blk = block; / self.blk = block;

    4、xxxusingBlock(blk_t blk) /  GCD的API用block做参数的

    变成weak之后 发现block结构体中的成员变量也变成weak了

    改为weak 持有weak变量

    array2在出变量作用域之后设为nil,所以三次输出都是0

    可用声明为weak来避免循环引用。

    看一下block截获基础类型变量和对象类型变量的区别

    __block int  val = 10;

    该变量转换为结构体__Block_byref_val_0

    同时转换后的文件头部多了___main_block_copy_0___main_block_dispose_0这两个函数定义,

    这两个函数内部调用了__Block_object_assign和_Block_object_dispose方法,

    __Block_object_assign方法中让Block持有__block变量

    这两个方法有个参数block_field_is_byref(绿色的)代表是assign了__block变量,如果是id类型,但是没有__block修饰符,则这里的值是BLOCK_FIELD_IS_OBJECT。

    具体的__Block_object_assign实现是这样的:

    这两个函数在main中并没有被调用,那么是何时进行了调用呢?

    当block从栈复制到堆上的时候,调用__main_block_copy_0,__block变量也从栈复制到堆上时,并被Block所持有。

    __block id obj = [[NSObject alloc] init];的情况

    __Block_object_assign函数将__block变量赋值给block成员变量,strong类型变量持有对象,从而block持有该对象

    只要__block变量在堆上存在,对象就会一直被持有。

    __block id __strong obj = [[NSObject alloc] init];  和不带__strong的情况一样

    总结一下就是:

    ARC下,Block中引用id类型的数据有没有__block都一样都是retain,而对于基础变量如int而言,没有的话无法修改变量值,有的话就是修改其结构体令其内部的forwarding指针指向拷贝后的地址达到值的修改。而MRC下,则都是拷贝一份指针。

    相关文章

      网友评论

          本文标题:读书笔记(二)

          本文链接:https://www.haomeiwen.com/subject/mluyqttx.html