Block的原理和使用

 我来答
户如乐9318
2022-06-12 · TA获得超过6636个赞
知道小有建树答主
回答量:2559
采纳率:100%
帮助的人:137万
展开全部
前言:最近看了好多block相关的东西,block在项目中很常见,想必大家也都比较熟悉,可是,细细想下,又有好多迷惑?为什么会产生循环引用? 为什么要用__block? __block到底是干什么的......如果你也有类似的困惑,那就跟我一起探究下吧。

首先探究下block的本质,他到底是个啥东东呢?

通过clang编译,我们可以看到block的内存布局,就是一个结构体,里面包含一个我么熟悉的isa指针,显然就是一个oc对象。它的底层结构就是:

通过class方法我们可以看到block有3种类型

NSGlobalBlock : 存放在数据段,没有访问auto变量(局部变量)的block(基本没啥用)

NSStackBlock:存放在栈区,访问了auto变量

NSMallocBlock:存放在堆区,NSStackBlock通过copy,从栈区拷贝到堆区

每一种block被copy后的结果

在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上。

MRC下block属性的建议写法

@property (copy, nonatomic) void (^block)(void);

ARC下block属性的建议写法

@property (strong, nonatomic) void (^block)(void);

@property (copy, nonatomic) void (^block)(void);

当block内部访问了对象类型的趋同变量时

1.如果block在栈上,将不会对auto变量产生强引用

2.如果block被拷贝到堆上

   2.1 会调用block内部的copy函数

    2.2 copy 函数内部会调用_block_object_assign函数

    2.3 _block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)作出相应的操作,形成强引用还是弱引用。

3.如果将block从堆上移除

    3.1 会调用block内部的dispose函数

    3.2 dispose函数会调用_Block_object_dispose函数

    3.3 _Block_object_dispose函数自动释放引用的auto变量

当我们想在block内部修改auto变量的时候,总是需要用__block来修饰,这是为什么呢?

3.1 为什么不能直接在block内部修改auto变量?

当block捕获auto变量的时候,只是获取了它的值,没有获取到它的地址,所以不能进行修改。

那么我们都知道为了解决block无法修改auto变量的问题,需要用到__block来修饰auto变量。

3.2 那么__block做了什么呢?

被__block 修饰过的auto变量会生成一个结构体

其中__main_block_impl_0是个新的结构体,里面包含一个age指针,这是又是一个结构体__block_byref_age_0,这个结构体的age 才是我们真正传入的值,forwarding也是一样的结构体,他是指向自己的一个指针

总结下__block的使用:

1.__block可以用于解决block内部无法修改auto变量值的问题

2. __block不能修饰全局变量,静态变量

3. 编译器会将__block变量包装成一个对象

4.1 当block在栈上,并不会对__block变量产生强引用

4.2 当block被拷贝到堆时

    4.2.1 会调用block内部的copy函数

    4.2.2 copy函数会调用_Block_object_assign函数   

    4.2.3 _Block_object_assign函数会对__block变量行程强引用

4.3 当block从堆中移除时

    4.3.1 会调用block内部的disease函数

    4.3.2 dispose函数内部会调用_Block_object_dispose函数

    4.3.3 _Block_object_dispose函数会自动释放饮用的__block变量

双方互相持有对方,都无法释放,这就是循环引用

我们经常会想到的解决方案就是用__weak 修饰,下面看看还有哪些解决方法

6.1 ARC

6.1.1 用__weak、__unsafe_unretained解决

6.1.2 用__block解决(必须要调用block)

6.2 MRC

6.2.1 用__unsafe_unretained解决

6.2.2 用__block解决

看完后,心中好多疑惑大概都解决了,那下面几道面试题来回顾下

1.block的本质是什么?

答:封装了函数调用以及调用环境的oc对象

2.__block 的作用是什么?有什么需要注意的?

答:作用:__block可以用于解决block内部无法修改auto变量值的问题

       注意点: __block不能修饰全局变量,静态变量;在MRC环境中,不会被强引用。

3.block的属性修饰为什么是copy,使用block有哪些注意点?

答:block如果没有被copy,就不会在堆上,这样我们无法预知它的生命周期。只有将block被拷贝到堆上,我们才能管理其生命周期,想什么时候释放都行。注:ARC环境下,strong和copy没有区别,为了跟MRC环境中一样,我们喜欢用copy。

     需要注意的是,使用block不要产生循环引用。解决循环饮用的方法之前都提到过。
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
威孚半导体技术
2024-08-19 广告
威孚(苏州)半导体技术有限公司是一家专注生产、研发、销售晶圆传输设备整机模块(EFEM/SORTER)及核心零部件的高科技半导体公司。公司核心团队均拥有多年半导体行业从业经验,其中技术团队成员博士、硕士学历占比80%以上,依托丰富的软件底层... 点击进入详情页
本回答由威孚半导体技术提供
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式