美文网首页
block详解

block详解

作者: 嘿_原来你也在这里 | 来源:发表于2021-07-16 07:36 被阅读0次

block本质:

每个OC对象内部都有isa指针,block也不例外;block其实就是封装函数调用,以及函数调用环境的OC对象。

block底层结构:

block底层结构

block的类型:

内存几大区域

常见的有以下三种block:

NSMallocBlock :存放在堆区的 Block

NSStackBlock  : 存放在栈区的 Block

NSGlobalBlock : 存放在全局区的 Block

当block 没有截获外部变量、截获全局变量的都是属于全局区的 Block,即 GlobalBlock;其余的都是栈区的 Block,即 StackBlock;

对于全局区的 Block,是不存在作用域的问题,但是栈区 Block 不同,在作用域结束后就会 pop 出栈,__block 变量也是在栈区的,同理作用域结束也会 pop 出栈。

为了解决作用域的问题,block 提供了 copy 函数,将 block 从栈复制到堆上,在 MRC 环境下需要我们自己调用 block_copy  函数,这里就是为什么 MRC 下,我们为什么需要用 copy 来修饰 Block 的原因。

MRC情况下:

MRC的情况下

ARC情况下:

编译器会根据情况自动添加copy,将栈上的block拷贝到堆上,比如以下情况:

1、block作为函数返回值

2、block赋值给__strong指针

3、block作为Cocoa API中的方法名含有usingBlock的方法参数时

4、block作为GCD API参数时

每一种类型的block调用copy后的结果如下:

使用copy结果示意图

block捕获机制:

block捕获机制 捕获auto、static局部变量

因为auto的局部变量在离开作用域会销毁,所以block内部使用值传递的方式捕获到,因此在block内部不能更改auto变量的值,像int因为值是直接存储在变量内存里面,所以不能更改;而static因为是指针传递所有能更改。

更改mArr内容 更改mArr指针地址

因为NSMutableArray 变量里面其实存的是指针地址,所以直接操作指针里面的内容是可以的,如果直接更改变量存储的指针地址就不行。

如果是全局变量不会捕获,不管在哪个函数都能直接访问;局部变量因为作用域的问题,可能存在跨函数访问所以会捕获。

如果block中引用实例变量(比如说name)不管是通过self.name还是_name,block都会捕获self对象.因为方法的调用默认传递两个参数(self,sel)所以self为局部变量,block引用局部变量都会捕获。

既然block对局部auto变量是值传递,那么如果想要在block内部修改auto变量怎么修改?

如果block外部变量是auto变量可以使用__block;如果是static静态变量 或者全局变量,则不需要修饰也能更改。(参考捕获机制)

原理:在ARC环境下,编译器会尽可能给我们自动添加 copy 操作。使用copy从栈复制到堆上,__block 修饰的变量也会从栈复制到堆上;为了结构体 __block 变量无论在栈上还是在堆上,都可以正确的访问变量,我们需要 forwarding 指针forwarding指针的作用:保证当我们将 Block 从栈拷贝到堆中,修改的变量都是同一份。

forwarding原理:在 Block 从栈复制到堆上的时候,原本栈上结构体的 forwarding 指针,会改变指向,直接指向堆上的结构体。这样子就可以保证之后我们都是访问同一个结构体中的变量,这里就是为什么 __block 修饰的变量,在 Block 内部中可以修改的原因了。

forwarding指针

__block底层实现:

当__block变量在栈上时:

并不会对指向的对象产生强引用。

当__block变量被copy到堆上时:

copy函数内会调用_Block_object_assign函数;_Block_object_assign函数会根据auto变量(对象类型)的修饰符(__strong,__weak, __unsafe_unretained)做出相应的操作形成强、弱引用;

当__block变量被从堆上移除时:

会调用Block内部的dispose函数 dispose函数内部会调用_Block_object_dispose函数 _Block_object_dispose函数会自动释放引用的auto变量,类似于release。

block引起循环引用场景:

当 A 持有 B,B 又持有 A,这个时候就会出现循环引用。Block 对于外部变量都会追加到结构体中,所以在实现 Block 时候需要注意这个问题。

解决方案:

ARC 环境一般我们用 __weak 来打破,MRC 环境的话,我们可以使用 __block 来打破循环引用。

相关文章

  • iOS Block实例

    iOS之Block详解:Block详解 ViewController.h(ARC) ViewController....

  • Block - block简单的使用

    参考文档 iOS Block详解 一、忘记block格式? 样例一.png 样例二.png 二、Block的定义 ...

  • SDWebImage4.0源码探究(二)具体代码拓展

    代码一 知识点:block参考:iOS中block的详解weakSelf、strongSelf <转自唐巧>Blo...

  • 关于block的理解

    block的类型详解 关于block的知识,在网络上的资料那是相当的多。不过这里还是想来谈谈自己对block的理解...

  • iOS 题目详解 部分三

    主要讲解Block 内部使用strongSelf的理由和用法 iOS 题目详解 部分一iOS 题目详解 部分二...

  • Block详解

    1.Block定义及使用 首先看下Block的定义和使用。 实际使用方法 Block看起来比较复杂,在OC中实际上...

  • Block详解

    1️⃣Block的修饰 ARC情况下( ARC是iOS 5推出的新功能,全称叫 ARC(Automatic Ref...

  • block详解

    __weak typeof(self) weakSelf = self;self.handler = ^{type...

  • Block详解

    __block说明符 Block只能保存局部变量瞬间的值,所以当我们尝试修改截获的自动变量值,就会报错。例如: 该...

  • Block详解

    block的定义,调用等就不介绍了,自行去查资料。 本文介绍内容: 1.block的底层数据结构2.block的类...

网友评论

      本文标题:block详解

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