iOS Block的三种类型 globalBlock、stackBlock 、mallocBlock 区别


在 ARC 中,捕获了外部变量的 block 的类会是 __NSMallocBlock__ 或者 __NSStackBlock__,如果 block 被赋值给了某个变量,在这个过程中会执行 __Block__copy 将原有的 __NSStakeBlock__ 变成 __NSMallocBlock__ ;但是如果 block没有赋值给某个变量,那他的类型就是 __NSStakeBlock__ ;没有捕获外部变量的 block 的类会是 __NSGlobalBlock__ 即不再对上,也不在栈上,它类似 C 语言函数一样会在代码段中。

在非 ARC 中,捕获了外部变量的 block 的类会是 __NSStackBlock__ ,放在栈上,没有捕获外部变量的 block 时与 ARC 环境下情况相同。

block 中的 isa 指向的是该 block 的 Class 。在 block runtime 中,第一了6种类型:

_NSConcreteStackBlock     栈上创建的block

_NSConcreteMallocBlock  堆上创建的block

_NSConcreteGlobalBlock   作为全局变量的block

_NSConcreteWeakBlockVariable

_NSConcreteAutoBlock

_NSConcreteFinalizingBlock

我们能接触到的主要是前三种,后三种用于 GC 不再讨论...

当 struct 第一次被创建时,它是存在于该函数的栈帧上的,其 Class 是固定的 __NSStackBlock 。其捕获的变量是会赋值到结构体的成员上,所以当 block 初始完成后,捕获到的变量不能更改。 

当函数返回时,函数的栈帧被销毁,这个 block 的内存也会被清除。所以在函数结束后,如果仍需要这个 block ,就需要用到 Block_copy() 方法将它拷贝到堆上。这个方法的核心动作是:申请内存,将栈数据复制过去,将 Class 改一下,最后向捕获到的对象发送 retain ,增加 block 的引用计数。

1.全局 block 

定义在函数外部的 block 是 global 类型的

定义在函数内部的 block ,但是没有捕获任何自动变量,那也是全局的。

全局静态 block,不会访问任何外部变量,执行完就销毁。

typedef

int(^blk_t)(int);

for(...){

blk_t blk = ^(intcount) {returncount;};

}或

^{ NSLog(@"Hello World!"); }();

2.栈 block

保存在栈中的 block,当函数返回时会被销毁,和第一种的区别就是调用了外部变量。

typedef void (^block_t)() ;

-(block_t)returnBlock{

    __block int add=10;

    return ^{printf("add=%d\n",++add);};

}

这是因为:block捕获了栈上的add自动变量,此时add已经变成了一个结构体,而block中拥有这个结构体的指针。即如果返回block的话就是返回局部变量的指针。而这一点恰是编译器已经断定了。在ARC下可以编译过,是因为ARC使用了autorelease了。

再说一个场景:

- (block_t) returnBlock{

    __block int add=10;

    block_t blk_h =^{printf("add=%d\n",++add);};

    return blk_h;

}

block_t bb = [self returnBlock];

bb();

这段代码,只是使用了一个自动block变量,可以编过,但是造成程序崩溃了。

如果在返回block的时候加上copy,可以输出正确的数值11

[UIView animateWithDuration:3 animations:^{ self.view.backgroundColor = [UIColor redColor]; }];

3.堆内存

保存在堆中的 block,当引用计数为 0 时会被销毁。例如按钮的点击事件,一直存在,即使执行过,也不销毁,因为按钮还可能被点击。直到持有按钮的View被销毁,它才会被销毁。

有时候我们需要调用 block 的 copy 函数,将 block 拷贝到堆上。如下代码:

- (id) getBlockArray{

    int val =10;

    return [NSArray arrayWithObjects:

        ^{NSLog(@"blk0:%d",val);},

        ^{NSLog(@"blk1:%d",val);},nil];

}

id obj = getBlockArray();

typedef void (^blk_t)(void);

blk_t blk = (blk_t){obj objectAtIndex:0};

blk();

这段代码在最后一行 blk() 会异常,因为数组中的block是栈上的。因为val是栈上的。解决办法就是调用copy方法。

这种场景,ARC 也不会为你添加 copy,因为ARC不确定,采取了保守的措施:不添加copy。所以ARC下也是会异常退出。

Block 在栈和堆中的区别

1.默认情况下,block 默认存储在栈中;如果将 block 进行一次 copy 操作,block 会转移到堆中。

2.如果 block 在栈中,block 访问了外界变量,那么不会对外界进行 retain 操作。

3.在 property 中使用 block 时,一般都是用 copy 修饰 block ,将 block 拷贝到堆上,减少无意中的堆 block 释放。

Copy 的作用

1. 防止外界修改内部数据

2.可以使用 copy 保存 block ,这样可以保住 block 中使用外界对象的生命。

Block的声明语法

一、block的声明

int multiplier = 10;

int (^MyBlock) (int) = ^(int num) { return num*multiplier };

int Myblock 是块对象,返回整形值

"^" 符号将 MyBlock 声明为一个块对象

(int) 它有一个参数,参数的类型也是整形

^(int num) 参数的名称是num

^(int num) { return num*multiplier } 这是定义块对象的语法结构,这部分就是赋给MyBlock变量的值。

{ return num*multiplier } 这是块对象的主体部分

1.写在方法里作为局部变量

returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};

returnType是返回值

blockName是block名称

parameterTypes是参数

//无参数无返回值

void (^myblock)() = ^()

{

    NSLog(@"Hello, World!");

};

myblock();


//带参数无返回值

void (^myblock2)(NSString *string) = ^(NSString *string){ NSLog(@"%@",string);};

myblock2(@"Hello, World myblock2!");


 //无参数有返回值

int (^myblocksss)() = ^(int i){return 12;};

int c = myblocksss();

NSLog(@"%i",c);


//有参数有返回值

int (^myblock3)(int) = ^(int i){ return 12 * i; };

int i = myblock3(3);

NSLog(@"%i",i);


2.作为类的属性

@property(nonatomic,copy) returnType (^blockName)(parameterTypes)

returnType是返回值

blockName是block名称

parameterTypes是参数

3.作为方法参数

- (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;

returnType是返回值

blockName是block名称

parameterTypes是参数

4.调用方法是传入的参数

[self someMethodThatTakesABlock:^returnType (parameters) {...}];

returnType是返回值

blockName是block名称

parameterTypes是参数

5.自定义Block类型

typedef returnType (^TypeName)(parameterTypes);

TypeName blockName = ^returnType(parameters) {...};

returnType是返回值

blockName是block名称

parameterTypes是参数

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

推荐阅读更多精彩内容

  • Block基础回顾 1.什么是Block? 带有局部变量的匿名函数(名字不重要,知道怎么用就行),差不多就与C语言...
    Bugfix阅读 6,762评论 5 61
  • iOS代码块Block 概述 代码块Block是苹果在iOS4开始引入的对C语言的扩展,用来实现匿名函数的特性,B...
    smile刺客阅读 2,344评论 2 26
  • block.png iOS代码块Block 概述 代码块Block是苹果在iOS4开始引入的对C语言的扩展,用来实...
    全栈农民工阅读 589评论 0 1
  • 思忖着想了好久的故事和逻辑, 不抵念及你时的心率欢喜。 顿口结舌的情话出口成了 木词讷语的麻瓜一样 你说傻逼啊, ...
    良乆囍阅读 316评论 0 5
  • 曾在寺中偶见佛祖真身,佛祖闻我有缘,许我两世为人看破因果红尘。 第一世。 我出生在一座小镇富豪家中,自幼被迫苦读文...
    酸酸的煤球阅读 1,176评论 1 5