block 几乎所有行为的汇总

概述
闭包,可以捕获代码。block对象常量块外的属性 非标准c组成部分。
源码部分不粘了 - 主要证明两点 1 是个对象, 2 内部有一个结构体用来存自动变量。
自己的一份流水账笔记,囊括了基本block的全部行为。

三种block
NSConcreteGlobalBlock
如果引用的不是外部变量那么都是这种,即使引用的是全局、静态。
这种block 不需要保存变量,一种是内部的,一种是全局的,都是可以在block的生命周期内拿到的。
block 没引用需要保存的变量,就不会开辟栈空间, 它在全局区。
最开始考虑他是一段代码会不会直接存在text段,但他是个对象所以还应该是全局区。

NSConcreteStackBlock
变成这种类型,只有一个理由,那么就是block的结构体中保存了自动变量(全局、静态都不需要保存,而在block块内变量更是和block 一个生命周期 所以更不需要保存)。
内部有一个结构体,保存了自动变量,block依旧在栈上。

NSConcreteMallocBlock
当copy行为产生,block就会是这个类型的,而且会对所有内部持有的对象,引用计数+1。
这种block是对NSConcreteStackBlock的升级,把NSConcreteStackBlock这种block的结构体保存到了堆区。
如果这种block没有被持有,所有block中的对象也都不会增加引用计数。

在arc下
当一个block被外部强引用的指针引用 并且内部有一个对外部变量引用的条件下,他会产生一个copy行为,这个行为使它变成NSConcreteMallocBlock
只要有强引用的block 都会产生copy 行为。

但是当外部引用的指针是一个弱指针,那么它还是NSConcreteStackBlock 类型

如果block中没有引用外部变量,那么就会直接是个NSConcreteGlobalBlock 而不论外部引用的指针是不是强引用

在mrc下
由于手写内存管理,release retain, 所以强引用并没有参与指针的copy行为。
在mrc下 只有当block 引用了自动变量,并且对该block使用了 Block_copy() 这个block 才是NSConcreteMallocBlock 类型
如果引用了自动变量而没有copy行为,那么是NSConcreteStackBlock类型

所谓持有
arc下持有block是用一个强指针引用block,mrc下持有block是对block 使用 block_copy。 除此之外,block不会存在堆区

block stackBlock;    {        
    NSInteger val = 10;        
    stackBlock = ^{                NSLog(@"%zd", val);            };
} 
    stackBlock();

没崩溃,
分析 : {}不是一个函数调用,虽然执行了, 不会弹栈。

__block 的行为
我们一般说block对外部变量的使用 是一个捕获的行为。
是说值保存在block自己的一个结构体中,所以不能对这个值进行修改操作。
当使用__block的时候,其实是对外部对象进行了一个指针引用,也就是在block内部是对指针进行一个保存,对这个指针的一切操作都会影响外部(类似引用)。

mrc 下的 __block 行为
如果block 中引用了外部变量,那么即使该变量是被 __block 修饰的 该block 也是 NSConcreteStackBlock 类型,如果再被 Block_copy 修饰,那么它将会是NSConcreteMallocBlock 类型

arc 下的 __block 行为
block 的存储位置,基本取决于指针的强弱,而不取决于 引用的外部自动变量是否是 __block

一个现象
两个不同堆内存的block 可以共用 __block 修饰的自动变量
//测试两个block 之间 对 __block 修饰的自动变量的引用关系
//mrc 下,即使两个变量对不同的block copy到不同的堆内存,这两个block 对相同的通过 __block 引用的变量的访问地址都是一致的 , 这怎么实现的??? 难道是一张__block变量的表吗? 是不是通过__block 修饰后这个变量就不存在栈区了,而是全局区, 也不再栈区? 证明不是,即使通过__block 修饰,他也是在栈区。

mrc下 __block 修饰的自动变量在block中的内存管理方式。

NSObject *objc = [[NSObject alloc] init];
block copyObjc = Block_copy(^{
      NSLog(@"%@", objc);
});

也即是执行完了 第三行,block内部结构体会对objc这个变量的值进行一个复制。
那么当block 被持有时,block对内部的访问到的对象也是有一个持有(retain) 的操作了。
那么也就是说在mrc下,这个复制的行为会导致这个对象的引用计数+1,
而当objc 是 __block 修饰的时候,引用计数就不会 +1 ,因为内部结构体存的是指针的引用。

arc 行为 arc 行为非常简单
当持有block的指针是一个强指针时 block 内访问到的所有外部对象都有强指针引用,即使block引用的外部变量是 被__block 指针引用修饰。
当持有block的指针是一个弱引用是 block 内访问到的所有外部对象都没有被强引用,甚至这个block都不是一个 mallocBlock,而是一个stackBlock

_NSConcreteGlobalBlock 全局的静态 block,不会访问任何外部变量。
_NSConcreteStackBlock 保存在栈中的 block,当函数返回时会被销毁。
_NSConcreteMallocBlock 保存在堆中的 block,当引用计数为 0 时会被销毁。

Block_copy 在mrc下有一个特殊行为
这个函数是用来把 block 放到堆区的,那么也就是说,参数应该是存在栈内存上的一个block
如果参数是一个存在堆或者全局区的block 那么 这个Block_copy 函数的行为会使存在堆内存上的block的引用计数 + 1 。
如果block本身是 _NSConcreteGlobalBlock ,那么使用了 Block_copy 之后 她依旧在 _NSConcreteGlobalBlock

属性用copy 的行为
mrc
copy 直接对 block 使用 Block_copy 行为 , 也是系统推荐的 方式。
retain block 依旧保持原来类型, 引用计数不会增加
assign 依旧保持原来类型,引用计数不会增加
strong (mrc 下 可以用 strong 了, 是不是也就说 如果都是用 strong 那么mrc 和 arc 没区别了? 应该不是,因为arc mrc 是编译选项,编译时期只不过做了 添加 release retain 的操作,如果不 打开 arc, 那么就要自己添加了 retain release 了), 和copy 行为一样了,把block 放到堆内存了 , 并且block 类型也变成 malloc block 了。

arc 下
copy 和 strong 行为一致
因为block 是不可变对象,所以都只是增加了一个强引用而已,arc 下 block 只要有强引用并且内部引用了自动变量,他就在堆区。
weak 依旧保持block 原样, 没有copy行为。

一些细节

如果block在函数外部,那么存储在全局区。
包括block变量头 和 block对象常亮块。

多次执行block 也同样是一个block对象常量块,不会多次生成存储区域。
block在递归中的行为,是多次递归生成存储区域,因为栈内存没有被弹栈,而且之前的区域一直被占用所以会开辟多个存储区域。

官方文档 查 working 关键字,一般会是一些原理。
uiApplication 强引用着 Appdelegate 强引用着 window 强引用着 根控制器

block 使用场景
1.保存代码
// 1.在一个方法中定义,在另外一个方法调用
// 2.在一个类中定义,在另外一个类中调用
2.作为方法参数

  • (void)Cacultor:(NSInteger(^)(NSInteger result))block;

注意点
arc 下,block会对内部使用到的所有强指针变量都强引用。
一般的处理是在外部把 需要引用到的对象,赋给一个弱引用再进行引用。

    __weak typeof(self) weakSelf = self;       
_block = ^{
           __strong typeof(weakSelf) strongSelf = weakSelf;                       
          dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                        NSLog(@"%@",strongSelf);                   
});           };   
 _block();

ARC:管理block
只要block引用外部局部变量,block放在堆里面
block使用strong.最好不要使用copy
为什么arc下block就放到堆区了呢? 因为有强引用。
如果block没有强引用, 那么依旧是 保存在全局区,如果引用到局部变量,依然保存在栈区。

MRC 下 block管理原则
使用copy来管理。
如果使用了retain ,那么block体(也就是对象) 还是存在栈区(如果内部使用到了需要保存的局部变量,否则block体存在全局区)。
因为block使用是一块代码,全局区。
但是当 使用到了 copy ,那么会把 block体 拷贝到堆区。

总结
block的管理原则 只有一个
当内部有需要保存的变量,那么block在栈区开辟空间保存临时变量。
如果没有需要保存的变量,那么保存在代码区。
当有强引用 或是 copy的时候,block 会存储在堆区。

一些写法

__weak ViewController *weakSelf = self;
self.retainBlock = ^ {
 ViewController *strongSelf = weakSelf;
 NSLog(@"%@", strongSelf);
};

只有当引用的外部对象是弱引用的情况下,block是 NSConcreteStackBlock,block 存在栈区,所以没有循环引用。

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

推荐阅读更多精彩内容