探究iOS中Block的本质

在ios开发中block代码块是一个非常实用东西,block给程序开发提供了非常多的便捷之处。这篇文章就对于block的本质进行一些讨论。

首先明确一个概念,什么是block——block是将函数及其执行上下文封装起来的一个对象。在block实现的内部,有很多变量,因为block也是一个对象,那肯定也是之前文章中说过的Objc_object类的一个子类。其中包含了诸如isa指针,imp指针等对象变量,还有储存其截获变量的对象等。其block内的实现内容,会被c++封装成一个方法,当一个block被调用时,会根据block对象查找内部的函数实现指针,从而调起对应的方法,来完成一次block的调用。

其次,梳理的一个概念为block内部的截获变量规则。例如,block内部使用了一个外部提供的变量,那么对于这个变量类型的不同,其截获方式也会存在差异。

总体而言,block截获的变量分四大类:局部变量、静态局部变量、全局变量、静态全局变量。

对于后两种全局变量和静态全局变量,block是不会截获的,而是直接拿来用。

我们来梳理前两种、局部变量和静态局部变量。在block截获局部变量中,又分两种情况,分别是对象型局部变量与基本数据类型局部变量。对于对象型的局部变量,block是对其所有权关键字一起进行截获,对于基本数据型的局部变量是截获其值,而对于静态局部变量,block内部是通过截获其指针的方法进行操作的。

说到了截获变量就不得不说所有权关键字——__block了。

__block所有权修饰符的对象主要用来在block内部使用,通常在block内部对截获变量进行赋值需要在被使用变量前加上Block修饰符修饰,否则会引起编译报错。而静态局部变量,全局变量和静态全部变量是不需要增加__block关键字的。而__block的实质是将一个变量作为一个__block对象储存在block内部,并且内部有一个forawarding指针指向自己,另外这个__block对象内部也会有isa指针,储存相应的值,占用内存空间等,各种相关的变量。

下面来讨论一下block的相关内存管理问题

在不同内存区域的block对象存在三种不同的类型:1.__NSConcreteStackBlock,2.NSConcreteGlobalBlock,3.NSConcreteMallocBlock

这三种block对象分别储存在栈区、已初始化数据区与堆区中。

对这三种block进行copy操作会产生三种不同的结果:1.在堆区产生一个相同的block对象,2.什么也不做,3.给原有block对象引用计数+1.

__block对象中的__forwarding永远指向自己,而在栈区中被copy过的__block对象,其__forwarding指针指向其堆区中的__block对象。所以这也是如果要定义一个block类型的属性,其关键字需要使用copy的原因。因为当栈上block作用域结束的时候,其内存空间会被回收,这时候再调用了相应的block属性的话,会产生野指针等不可遇见的崩溃情况。需要补充的的一句是,当一个block对象被copy时,其内部__block对象一样会被copy,且栈区__block对象__forwarding指针会指向堆区,这也是__forwarding指针存在的意义:无论在什么内存位置,都能顺利的访问一个__block对象。

还有一个需要提及的是,在MRC模式下,使用__block还可以起到一个弱引用的功效,其修饰的对象被引用不会造成引用计数+1。而在ARC下需要注意__block的循环引用问题。其解决方法可以手动断环将__block置为nil或者使用__weak修饰符替代。

 

 

本文章由作者原创,未经允许禁止转载

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值