深入研究block

最近在看SDWebImage的源码。发现block这块的知识很深,源码里用的有些地方不知道什么作用。所以研究了下。

深层分析Block的实质:它是Objective-C对象。

block 实际上就是 Objective-C 语言对于闭包的实现,闭包就像是C++中的函数指针。为什么说Block其实就是Objective-C对象,因为它的结构体中含有isa指针。


1857952-1a62ba863ebfcf6e.jpg

通过该图,我们可以知道,一个 block 实例实际上由 6 部分构成:
isa 指针,所有对象都有该指针,用于实现对象相关的功能。
flags,用于按 bit 位表示一些 block 的附加信息,本文后面介绍 block copy 的实现代码可以看到对该变量的使用。
reserved,保留变量。
invoke,函数指针,指向具体的 block 实现的函数调用地址。
descriptor, 表示该 block 的附加描述信息,主要是 size 大小,以及 copy 和 dispose 函数的指针。
variables,capture 过来的变量,block 能够访问它外部的局部变量,就是因为将这些变量(或变量的地址)复制到了结构体中。

block的分类

NSConcreteGlobalBlock全局Block

全局Block存储在全局区。在编译期间就已经决定了,如同宏一样。
没有用到外界变量,或者只用到全局变量、静态(static)变量的block就是全局block。
对于全局block,有没有指针引用都不影响。

D61F5E3D-C056-4ECC-ADAD-CCEC8612D6A6.png

NSConcreteStackBlock栈Block

生命周期由系统控制,函数返回即销毁
用到局部变量、成员属性\变量,且没有强指针引用的block都是栈block


屏幕快照 2017-08-05 下午3.58.04.png

我们已经知道了NSConcreteStackBlock,那么它和NSConcreteGlobalBlock有什么区别呢?难道仅仅是引用了外部变量与否的区别吗?答案是否定的.
其实NSConcreteStackBlock内部会有一个结构体__main_block_impl_0,这个结构体会保存外部变量,使其体积变大。而这就导致了NSConcreteStackBlock并不像宏一样,而是一个动态的对象。而它由于没有被持有,所以在它的内部,它也不会持有其外部引用的对象。
证明一下

屏幕快照 2017-08-05 下午4.14.33.png

看到了吧,引用计数没变,发现指针的地址&obj在block中的和在block外的不一样。验证了__main_block_impl_0,这个结构体会保存外部变量。

NSConcreteMallocBlock堆Block

NSConcreteMallocBlock其实就是一个栈block被copy时,将生成NSConcreteMallocBlock。

屏幕快照 2017-08-05 下午4.34.05.png

NSConcreteMallocBlock是会持有外部对象的

屏幕快照 2017-08-05 下午4.40.41.png

看到了吧,只要这个NSConcreteMallocBlock存在,内部对象的引用计数就会+1。

__block 关键字

屏幕快照 2017-08-05 下午4.48.20.png

没错,前文说过,block引用外部是以捕获的形式来捕捉的,而没有声明__block,则会将外部变量copy进block,若用了__block,则是复制其引用地址来实现访问。这就是为什么声明了__block,在block内部改变就会对外有影响的原因了。一个是值传递,一个是引用传递。

注意!!这里需要知道的是,在MRC环境下,如果没有用__block,会对外部对象采用copy的操作,而用了__block则不会用copy的操作。

屏幕快照 2017-08-05 下午4.58.51.png

从更底层的角度来说,在MRC环境下,__block根本不会对指针所指向的对象执行copy操作,而只是把指针进行的复制

而在ARC环境下,对于声明为__block的外部对象,在block内部会进行retain,以至于在block环境内能安全的引用外部对象,所以要谨防循环引用的问题!

ARC下的 block

大家普遍会认为ARC下不存在NSConcreteStackBlock,这是因为本身我们常常将block赋值给变量,而ARC下默认的赋值操作是strong的,到了block身上自然就成了copy,所以常常打印出来的block就是NSConcreteMallocBlock了。所以在ARC下,大部分的应用场景下,几乎可以说是全部都为NSConcreteMallocBlock或者是NSConcreteGlobalBlock。

屏幕快照 2017-08-05 下午5.24.10.png

关于block作为属性用什么修饰。其实用copy和strong都可以的,strong修饰其实也是copy。但是苹果建议我们用copy。我一我们一般写都用copy修饰block。

block 的循环引用问题。

我们知道NSConcreteMallocBlock是会持有外部变量的,而此时如果它所持有的外部变量正好又持有它,就会产生循环引用的问题。

屏幕快照 2017-08-05 下午5.20.56.png

self强引用myBlock, myBlock强引用了self,所以导致self无法释放。

你可以用__weak(ARC)或__block(MRC)来解决:

屏幕快照 2017-08-05 下午5.30.16.png

block对于以参数形式传进来的对象,不会强引用

屏幕快照 2017-08-05 下午5.34.59.png

哈哈没看到有黄色的⚠️。所以不会强引用。

扩展文献

深入研究Block捕获外部变量和__block实现原理
谈Objective-C block的实现

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容