美文网首页
Block探索

Block探索

作者: 灰溜溜的小王子 | 来源:发表于2020-06-28 15:42 被阅读0次

一、什么是Block?

Block是将函数及其执行上下文封装起来的对象。

例如:

NSInteger num = 3;
void (^block)(NSInteger ) = ^(NSInteger n){
    NSLog(@"---%d",num * n);
};
block(2);
NSLog(@"%@",block);

eg:clang -rewrite-objc 深入研究

clang -rewrite-objc .m测试文件如下

NSInteger num = 3;
    void (*block)(NSInteger ) = ((void (*)(NSInteger))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, num));
    ((void (*)(__block_impl *, NSInteger))((__block_impl *)block)->FuncPtr)((__block_impl *)block, 2);
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_4j_v597272j6kb0q7g5x72k3xhw0000gn_T_main_3ecbdc_mi_1,block);

block类型如下:

struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
NSInteger num;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSInteger _num, int flags=0) : num(_num) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};

static void __main_block_func_0(struct __main_block_impl_0 *__cself, NSInteger n) {
NSInteger num = __cself->num; // bound by copy

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_4j_v597272j6kb0q7g5x72k3xhw0000gn_T_main_3ecbdc_mi_0,num * n);
    }

static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
block实质上就是个对象 __block_impl结构体 __block_impl结构体为block内部有isa指针,所以说其本质也是OC对象block内部则为: 内部规则 所以说Block是将函数及其执行上下文封装起来的对象既然block内部封装了函数,那么它同样也有参数和返回值

二、Block变量截获

1、局部变量截获是值截获。
比如: 局部变量值捕获 这里的输出是6而不是2,原因就是对局部变量num的截获是值截获。同样,在block里如果修改变量num,也是无效的,甚至编译器会报错。 image.png 打印为1,2,3局部对象变量也是一样,截获的是值,而不是指针,在外部将其置为nil,对block没有影响,而该对象调用方法会影响
2、局部静态变量截获是指针截获。 image.png

输出为2,意味着num=1这里的修改num值是有效的,即是指针截获。同样,在block里去修改变量m,也是有效的。

3、全局变量,静态全局变量截获:不截获,直接取值。
我们同样用clang编译看下结果。 各变量捕获情况
编译后: 各变量捕获情况 (impl.isa=&_NSConcreteStackBlock;这里注意到这一句,即说明该block是栈block)可以看到局部变量被编译成值形式,而静态变量被编成指针形式,全局变量并未截获。而__block修饰的变量也是以指针形式截获的,并且生成了一个新的结构体对象:
该对象有个属性:num5,即我们用__block修饰的变量。这里__forwarding是指向自身的(栈block)。一般情况下,如果我们要对block截获的局部变量进行赋值操作需添加__block修饰符,而对全局变量,静态变量是不需要添加__block修饰符的。另外,block里访问self或成员变量都会去截获self
三、Block的几种形式

分为全局Block(_NSConcreteGlobalBlock)、栈Block(_NSConcreteStackBlock)、堆Block(_NSConcreteMallocBlock)三种形式其中栈Block存储在栈(stack)区,堆Block存储在堆(heap)区,全局Block存储在已初始化数据(.data)区

1、不使用外部变量的block是全局block 全局block
2、使用外部变量并且未进行copy操作的block是栈block 栈block
日常开发常用于这种情况
3、对栈block进行copy操作,就是堆block,而对全局block进行copy,仍是全局block
比如堆1中的全局进行copy操作,即赋值 全局block赋值操作仍是全局block 而对2中的栈block进行赋值操作 栈block copy之后为堆block
对栈block copy之后,并不代表着栈block就消失了,左边的mallock是堆block,右边被copy的仍是栈block 输出:NSStackBlock,NSMallocBlock
即如果对栈Block进行copy,将会copy到堆区,对堆Block进行copy,将会增加引用计数,对全局Block进行copy,因为是已经初始化的,所以什么也不做。

另外,__block变量在copy时,由于__forwarding的存在,栈上的__forwarding指针会指向堆上的__forwarding变量,而堆上的__forwarding指针指向其自身,所以,如果对__block的修改,实际上是在修改堆上的__block变量。

即__forwarding指针存在的意义就是,无论在任何内存位置,都可以顺利地访问同一个__block变量

另外由于block捕获的__block修饰的变量会去持有变量,那么如果用__block修饰self,且self持有block,并且block内部使用到__block修饰的self时,就会造成多循环引用,即self持有block,block持有__block变量,而__block变量持有self,造成内存泄漏。

如果要解决这种循环引用,可以主动断开__block变量对self的持有,即在block内部使用完weakself后,将其置为nil,但这种方式有个问题,如果block一直不被调用,那么循环引用将一直存在。所以,我们最好还是用__weak来修饰self

相关文章

  • block分析(下)

    block通过clang分析 带着下面的疑问,我们去探索block原理 探索block底层源码 block在底层是...

  • Block探索

    随着苹果越来越多的API开始提供block的写法,另外加上block在很多时候写起来确实很方便,因此block越来...

  • Block探索

    Block内存关系Block经典问题循环引用&解决Block底层分析Block底层HooK 程序占用内存分类 栈区...

  • Block探索

    一、什么是Block? Block是将函数及其执行上下文封装起来的对象。 例如: eg:clang -rewrit...

  • Block探索

    Block的分类 Block一共有6种类,常见的有三种。 上面这种block的打印结果为<__NSGlobalBl...

  • Block探索

    Block block 类型**1、全局block - **NSGlobalBlock**** **2、栈bloc...

  • iOS底层探索之Block(二)——如何解决Block循环引用问

    Block你知道几种?Block的循环引用你有几种解决办法呢? iOS底层探索之Block(一)——初识Block...

  • Block 对象探索

    Block对象是一段代码,先给出一个Block对象的示例: 看上去和C函数类型,都是在一个花括号内的一套指令,但是...

  • Block原理探索

    Block定义 闭包是一个函数(或指向函数的指针),再加上该函数执行的外部的上下文变量(有时候也称为自由变量)bl...

  • Block的探索

    Block的特性 保存一段代码块 随时随地的持有 匿名函数 —— block -> 对象 -> struct 自动...

网友评论

      本文标题:Block探索

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