简单写一下Block的实质

(本人的文章只说个人理解,如有错漏,不吝指正,感谢)

定义:带有自动变量的匿名函数。

这里我有两个问题,自动变量和匿名函数。

我们先研究他的函数再研究他的变量,所以先说匿名函数:

block其实就是普通的C函数,C函数是支持以指针形式访问的,但是C函数不支持方法不命名。


C函数的指针访问

如图,Block的匿名实现其实就是隐去了声明(int func(int num))与指针赋值(int(*funcMB)(int) =&func;)的过程,内部必然是同样需要函数名的,OC基于C。

Block隐去声明之后只能指针访问,那他同样需要声明指针,所以会有一步(typedef void(^func_Mirror)(int num);)的过程,他并不是声明指针,他是声明指针格式,等价于(int (* funcMB)(int))。如此就可以通过OC提供的匿名创建方法创建C方法并得到指定格式的指针。

我们来梳理一下Block的流程:

1.先声明匿名函数的指针类型,typedefvoid(^func_Mirror)(intnum);(此时并不具备函数实体,就像OC方法的声明与实现)

2.赋值并返回指针,_block=^(int num){};(此时初始化C函数并传入上下文)

3.通过指针传入参数并执行此C函数,_block(10);(这里的上下文与参数并不是相同的概念,上下文关系到函数的实现,在函数初始化时即确定上下文实际值,而函数初始化与实参是没有任何关系的,实参只需要在函数执行时传入)


测试代码


结果

由此,i在block初始化时被copy到C函数体中,与后续的i再无关系,而参数则会在每次执行block时都读取;

到这里,关于匿名的部分我的理解就说完了。

__block

1.普通的上下文变量无法被重新赋值,否则会编译不通过,这是因为上下文在block初始化的时候就需要确定值,使用OC的对象类型可以在block内部调用方法改变其值,block引用OC对象本质上是使用其指针,OC对象调用方法不会改变自身指针而是改变自身结构中的值,所以也就没有修改block的上下文,如果在block内部试图重新赋值OC指针,编译报错;

2.__block会让原类型变成__Block_byref_val类型,原值传入此类型作为属性,此类型变量成为block成员属性,block将通过copy与dispose管理其内存。(__Block_byref_val 是系统固有类型,非动态生成,只是动态生成此类对象)

内存

Block内部存在isa指针,本质上是OC对象的一种,它的class分为三种:_NSConcreteStackBlock,_NSConcreteGlobalBlock,_NSConcreteMallocBlock;

实现在方法内的是_NSConcreteStackBlock,实现在方法外的是_NSConcreteGlobalBlock,_NSConcreteMallocBlock由_NSConcreteStackBlock copy生成。

_NSConcreteStackBlock:写在方法里,存在栈上,使用时copy到堆,内部变量的 __forwarding(__block类型变量的self指针)指向堆,出方法废弃;

_NSConcreteMallocBlock:不显式声明,存在堆里,由栈block copy而来,copy时copy所有变量并引用,被其他对象引用,服从OC内存管理;

_NSConcreteGlobalBlock:写在方法外,存在.data区,无法截获自动变量,代码执行时声明,代码结束时释放,不需要内存管理。

copy

栈block使用时会自动调用copy方法复制到堆;例如:调用,返回,手动调用copy,retain,赋值等等;

例外情况:block作为参数传给方法时(参数被usingBlock修饰或GCD方法除外)

手动调起copy时:

堆block :引用计数+1; 栈block :copy到堆; 全局block :什么都不做;

__autoreleasing 与__block冲突;

循环引用(针对OC对象)

block内变量(或变量的方法与属性)与block互相持有会引起循环引用。

解决:__weak可以使block不持有对应变量,但变量可能提前释放,block不安全;

不用修饰词,相当于__strong,只要在block执行完毕之后将其置nil 就可以打破block对其的引用,但变量不安全,block外部,此变量也被置nil,其次有的变量(self)无法被置nil;

__block,__block会使block引用相对应的block属性,block属性与对应属性与block依然是循环引用,但可以通过给block属性赋值nil打破此循环,手动赋值nil保证变量不被提前释放,缺点,只有block属性被置nil时循环引用才被打破;

MRC/ARC

以上均是默认ARC环境下的结论,MRC下,__block使block不会retain(强引用)对应变量,主要用于避免循环引用。

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

推荐阅读更多精彩内容