iOS Block笔记总结

前言:

对block的简单笔记总结,
 

1.本质:

封装了函数调用和函数调用环境的对象
 
2.block结构:
 
 
3.block捕获变量:
由于需要跨函数访问变量,所以需要捕获变量,(防止访问时已被销毁)
 - auto变量(基本数据类型):值捕获,超出作用域就被销毁了
 - static变量:指针捕获,
 - 全局变量:直接访问
 - self,也属于局部变量,(每个方法默认参数(self,_cmd))
 
4.block类型:
 
block类型
环境
copy
存储区域
NSGlobalBlock
没有访问auto变量
什么也不做
程序的数据区域 .data
NSStackBlock
访问auto变量
从栈赋值到堆上
NSMallocBlock
NSStackBlock 调用copy
引用计数+1
 
5.block 的copy:
在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如以下情况:
- Block 作为函数的返回值
- 将block赋值给__strong指针时
- block 作为Cocoa API中方法名含有usingBlock的方法参数
- block作为GCD API的方法参数
 
6.block内部访问对象类型的auto变量:
当block内部访问了对象类型的auto变量时,
- 如果block是在栈上,将不会对auto变量进行强引用
- 如果block 被拷贝到堆上
- 会调用block内部的copy函数,
- copy函数内部调用 _Block_objct_assgin函数,
- _Block_objct_assgin函数会根据auto变量的修饰符(__strong,__weak,__unsafe_unretained)做出对应的操作,类似retain(强引用、弱应用)
如果block从堆上移除
- 会调用block中的dispose函数
- dispose函数内部调用_Block_objct_dispose函数
- _Block_object_dispose函数会自动释放引用的auto变量,类似于release
 
7.__block 修饰符
编译器会将__block修饰的变量包装成一个对象
  - __block 可以用于解决block内部无法修改auto变量值的问题
  - __block不能修饰 static、全局变量
- 当block在栈上是,并不会对__block对象强引用
- 如果block 被拷贝到堆上,对__block对象是强引用
- 当block被copy到堆上时,会调用block(desc)中的copy函数
- copy函数内部调用 _Block_objct_assgin函数,
- _Block_objct_assgin函数会对__block变量进行强引用(retain)
- 如果是对象类型时,在__block变量中也会存在 内存管理函数(copy,dispose)
- 当__block变量在栈中,不会对指向的对象产生强引用
- 当__block变量被copy到堆时,会调用__block中的copy函数,
- copy函数内部调用__Block_objct_assgin函数,该函数会根据对象的修饰符(__strong,__weak,__unsafe_unretained)做出对应的操作,类似retain(强引用、弱应用)(注意:仅限于ARC时会retain,MRC下不会retain)。

如果block变量从堆上移除
- 会调用block中的dispose函数
- dispose函数内部调用_Block_objct_dispose函数
- _Block_object_dispose函数会自动释放引用的__block变量,类似于release
如果是对象类型时,也会调用
- 会调用__block中的dispose函数
- dispose函数内部调用_Block_objct_dispose函数
- _Block_object_dispose函数会自动释放引用的auto变量,类似于release
 
注意:当block内部对应__block对象都是强引用,
struct __Block_byref_p_0 { // 包装成的结构体对象
  void *__isa;
__Block_byref_p_0 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 Person *p;
};

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_p_0 *p; // by ref 指向包装成的g结构体对象指针
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_p_0 *_p, int flags=0) : p(_p->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};


static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
}

 

 
结构:
 

 

 
 
 
8.__block 结构体对象内部的__forwarding指针
 
 
 
9.循环引用问题:
ARC:
__weak, 
__unsafe_unreatined,不会产生强引用,不安全,缺点:对象销毁后,指针不会自动指向nil
__block,缺点:必须手动调用执行block,并在block中把对象赋值nil,
MRC:
__unsafe_unretained
__block block内不会进行retain操作
 
 
 

 

 

 

 

posted @ 2020-07-08 10:49  新司机上路  阅读(290)  评论(0编辑  收藏  举报
本人qq1365102044,有问题欢迎沟通!