Block block基本概念 block的本质是一个OC对象 因为block底层结构的第一个成员实际上是一个isa指针。 block封装了函数调用和函数调用环境。 因为block的内部存储了block函数实现的入口地址(函数调用),还捕获了 block函数所用到的外部的一些变量(函数调用环境)。 @property (nonatomic, copy) void(^block)(void); 值捕获 1.局部变量会被block捕获 自动变量(auto),block通过值拷贝方式捕获,在其内部创建一个同类型变 量,并且将自动变量的值拷贝给block的内部变量,block代码块执行的时候,直 接访问它的这个内部变量。 静态变量(static),block通过地址拷贝方式捕获,在其内部创建一个指向同类 型变量的指针, 将静态变量的地址值拷贝给block内部的这个指针,block代码块 执行的时候,通过内部存储的指针间接访问静态变量。 2.全局变量不会被block捕获 block代码块执行的时候,通过全局变量名直接访问。 self值捕获 block 内部使用 self.age self会被捕获 block 内部使用 _age self会被捕获,_age 的写法等同与self->_age 内存位置 全局区 NSGlobalBlock 数据段 如果一个block内部没有使用/访问 自动变量(auto变量),那么它的类型即为 __NSGlobalBlock__,它会被存储在应用程序的 数据段 栈block NSStaticBlock 栈区 MRC :如果一个block有使用/访问 自动变量(auto变量),那么它的类型即为 __NSStaticBlock__,它会被存储在应用程序的 栈区 堆block NSMallocBlock 堆区 ARC :如果一个block有使用/访问 自动变量(auto变量),自动从栈区copy到堆 区,就可以转变成__NSMallocBlock__,它会被存储在堆区上 ARC下auto变量可能被释放了,影响block获取变量,所以干脆复制到堆上 对__NSMallocBlock__调用copy方法,就可以转变成__NSMallocBlock__,它会 被存储在堆区上 ARC栈copy到堆 1 在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上 ARC栈copy到堆2 1.block作为函数参数返回的时候 2.将block赋值给__strong指针的时候 3.block作为Cocoa API中方法名里面含有usingBlock的方法参数时 4.block作为GCD API的方法参数的时候 __xxx_block_copy_x( struct __main_block_impl_0*dst, // 拷贝之前栈空间的block struct __main_block_impl_0*src // 拷贝之后堆空间上的 block ); (1)CLPerson *person 对象局部变量在被block捕获后,出了作用域并没有自 动释放 【ARC环境-->堆上的block-->强指针CLPerson *person 】 没有显试weak修饰的相当于strong 强指针 会引用该对象,retain 后引用奇计数+1,当block释放时,通过 _Block_object_dispose 来计数-1 (2)使用弱指针__weak CLPerson *person 局部变量在被block捕获后,出了 作用域并 自动释放了 (3)__weak + __strong : 只有外部使用weak时,避免对象过早释放,而 block内 刚好有 【延迟方法】时,会无法获取对象,起到一个延迟释放作用 ARC:__block __block结构 struct __Block_byref_val_0 { void *__isa; // isa指针 __Block_byref_val_0 *__forwarding; int __flags; int __size; // Block结构体大小 int age; // 捕获到的变量 } __block只可以用来作用于auto变量,它的目的就是为了能够让auto变量能够在 block内部内修改,这才有了 __Block_byref_val_0 结构体 被捕获的对象不再直接操作,而是将其封装到 __Block_byref_val_0 结构体里 面,通过这个结构体来操作 变量。复制到堆上就是将结构体直接复制,然后修改 指针 __forwarding 栈block __forwarding 指针就是指向栈上的自己 栈 -> 堆block 栈上的__forwarding 指针就是指向堆上的__Block_byref_val_0 结构体 堆上的__forwarding 指针就是指向 堆上的自己 _block + 基本类型变量 int a 将int a包装在struct __Block_byref_a_0内部,这样block实际上捕获的是这个 struct __Block_byref_a_0,它可以被当作一个对象来看待,因此需要通过 retain 和 release 管理内存 __block + 对象变量 相比较基本类型变量,对象类型的变量被__block修饰后,底层所生成的 __Block_byref_xxx_x结构体里面多了两个函数指针, __Block_byref_id_object_copy和__Block_byref_id_object_dispos __block + __weak + 对象变量 加上了__weak,因此struct __Block_byref_xxx_x内部封装的就是一个指向对 象的弱指针CLPerson *__weak weakBlockPerson __strong 为避免循环引用使用 __weak, 但是常规都可能是多线程环境,对象可能被提前 释放,此时block内部有延时函数就会导致对象获取nil。 而__strong在Block内部修饰的对象,会保证在使用这个对象在scope内,这个对象 都不会被释放,出了scope,引用计数就会-1, __weak typeof(self) weakSelf = self; model.dataChanged = ^(NSString *title) { __strong typeof(self) strongSelf = weakSelf; strongSelf.titleLabel.text = title; // 多层嵌套 ,使用多次 __weak typeof(self) weakSelf2 = strongSelf; strongSelf.model.dataChanged = ^(NSString *title2) { __strong typeof(self) strongSelf2 = weakSelf2; strongSelf2.titleLabel.text = title2; }; };