OC总结篇 - Block

int multiplier = 6
int(^ Block)(int) = ^int(int num){
      return num* multiplier
};
Block(2);
Block
"Block是什么"
是将函数及其执行上下文封装起来的对象
内部有isa指针和FuncPtr函数指针
isa说明他是个对象,FuncPtr指针指向了函数实现

"Block调用是什么"
就是函数调用
当我们调用block(2)时,内部实现是
通过block结构体里面的函数指针,取出对应的执行体.将参数传递进来(block本身,2),然后进行内部调用
源码分析
"Block源码结构体"中包括以下内容,说明了Block为什么是对象以及是怎么将函数和执行上下文封装的

-block_impl结构体
            isa指针
            FuncPtr函数指针,指向我们在block花括号中的执行体
-block相关描述的结构体
-block中传进来的参数(局部变量)
"截获变量的特性的内部实现"
最上面的示例中,当截获了变量multiplier,是把它传到上述的block结构体中
注意❤️:一旦在block结构体中赋值了,再操作时就是对结构体中的变量操作了,不是对block外的变量操作了

若传进来:
局部变量基本数据类型                    - 在block结构体中,直接截获这个值,赋值给block内部使用
局部变量对象类型(不知道为啥成员变量也截获) - 在block结构体中,连同对象的修饰符一起截获,赋值给block内部使用  
注意❤️:block的循环引用,就是因为局部对象是联通修饰符一起截获的
静态局部变量                           - 在block结构体中,以指针形式截获,也就是说,如果在block的定义之后,对静态局部变量值进行修改,再调用block时,用的是最新的值
全局变量                              - 不在block结构体中
静态全局变量                           - 不在block结构体中
"截获变量总结"
局部变量基本数据类型  - 直接截获,传进来是什么就是什么,不会改变
局部变量对象类型     - 连同所有权修饰符一起截获
静态局部变量        -指针截获,值会改变
全局变量           -不截获,值会改变
静态全局变量        -不截获,值会改变
截获变量示例
__block修饰符

对截获变量进行赋值操作时需要添加__block
注意❤️:赋值不等于使用!!!

array = [NSMutableArray array]就是赋值,若在block内部调用的话,需要为外部的array声明添加__block修饰符
[array addObject:@!23]就是使用而不是赋值
"如何使用__block修饰符"

"以下变量的赋值操作,需要使用__block修饰的情况" 
添加__block之后,当外部变量值改了之后,block内部调用时也会更改
1. 在block内部对局部变量基本数据类型进行赋值操作时
2. 在block内部对局部变量对象数据类型进行赋值操作时

"以下变量的赋值操作,不需要__block修饰" 
1. 在block内部对静态局部变量进行赋值操作时
2. 在block内部对全局变量进行赋值操作时
3. 在block内部对静态全局变量进行赋值操作时

因为全局变量和静态全局变量都不涉及截获操作
静态局部变量是通过指针来使用的,操作的是block外部的变量,所以不需要修饰
"__block做了什么"
__block修饰的变量会变成对象
举个🌰,当我们执行这句代码"__block int num"之后 ,num不再是个int型,而是变成个结构体,包含如下
1. void* isa
2. int num
3. __forwarding指针
"_forwarding指针"
存在的意义
不论在任何内存位置,我们都可以通过_forwarding指针顺利的访问同一个__block变量
若没有对__block进行copy,那么操作的是栈上的__block变量
如果copy后,不论是在栈还是堆,我们对__block的修改活赋值,都是对堆上的__block进行的
栈上的__block变量的__forwarding指针,是指向__block自身
当block外部的num改变时,__forwarding指针会去block结构体中找到里面的num对象进行赋值,但要注意这是栈上的block才会这样
如下图
如果对__block变量进行copy操作后,会在堆上面产生完全一样的block变量
栈上的__forwarding指针指向堆上的__block变量,而堆上的__forwarding指针指向自身的__block
所以说,在经过了copy之后,只要对这个值进行了修改,__forwarding指针改的都是堆上的值
如下图
Block的内存管理
"block有哪几类"
impl.isa = NSConcteteStackBlock, isa会标记block是哪种类型

全局block = NSConcreteGlobalBlock        存放在内存的已初始化数据区域中
栈block = NSConcreteStackBlock           存放在内存的栈上面
堆上面的block = NSConcreteMallocBlock     存放在内存的堆上面
"对于block的copy操作"
全局block - copy后什么也不做
栈block - copy后会在堆上产生一个block
堆block - copy后会增加其引用计数

问题🛫:
P类中有个assign修饰的block,假如在方法A中,我们P.block = ^(int){***}
因为方法A是在栈上,执行完在内存中就销毁了,假如在后面我们又调用了P.block
就会崩溃!!!
"block的销毁"
栈block变量在作用域结束后就销毁了

当我们对栈上block进行copy之后,会在堆上产生一模一样的blcok,但分占了栈和堆两块内存空间,当作用域结束后,栈上的block会销毁,但堆上的不销毁
在MRC环境下,对栈上block进行copy后,会内存泄露,因为如果堆上的block没有其他变量指向,就会产生内存泄露

Block的循环引用
"为什么会产生循环引用"
在截获变量中,若对象P强引用block,block内部又截获了strong类型的数组对象,就会循环引用
"怎么打破循环引用"
__weak

__block修饰符引起的循环引用


注意MCBlock不是个block,只是个类名字
上图的问题是,在MRC下不会产生循环引用,但在ARC下会产生循环引用,引起内存泄露

解决方式
下图这个解决方案有个弊端,也就是如果我们很长时间都没有调用这个block的话,这个循环引用就一直存在

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

推荐阅读更多精彩内容

  • 参考 Block编译代码解读:block没那么难(一、二、三)iOS进阶——iOS(Objective-C) 内存...
    啊哈呵阅读 773评论 0 3
  • 一、Block的底层结构及本质 (1)block本质: 从代码可以看出,Block的本质就是NSObject. 也...
    王的for阅读 442评论 0 2
  • 1.block介绍 概念:block是将函数及其执行上下文封装起来的对象。下面将通过原码解析的方式理解概念Obje...
    细雨菲菲v阅读 404评论 0 0
  • BLOCK block的描述: 他是类似函数指针的一个代码块的内联封装, 他可以将一个函数体作为对象传递 bloc...
    Chris脑阅读 270评论 0 0
  • block的本质 block本质上也是一个OC对象,它内部也有个isa指针block是封装了函数调用以及函数调用环...
    斑驳的流年无法释怀阅读 260评论 0 2