iOS Blocks语法、变量及为什么选用copy修饰符

Blocks是C语言的扩充功能:带有自动变量(局部变量)的匿名函数;

匿名函数就是没有名称的函数。

1、Block语法和Block变量

C语言中的变量(根据作用域不同区分的):

1、自动变量(局部变量);

2、函数的参数;

3、静态变量(静态局部变量);

4、静态全局变量;

5、全局变量;

其中,静态变量(静态局部变量)、静态全局变量、全局变量是可以在函数的多次调用之间传递的变量。

Block语法,形式如下:(^ 返回值类型 参数列表 表达式)

^(void)  (int event)

{

      Printf(“buttonId:%d event=%d\n”, i, event);

}

Block语法与一般C语言函数定义相比,有两点不同:

1、没有函数名;

2、带^;

^:插入记号,便于查找

Block语法可以省略返回值类型;也可以省略参数列表类型;

省略返回值类型和参数列表类型后的语法格式为:^{}

函数指针的声明示例:

int (*funcptr) (int) = &func;

Block类型变量的示例:

int (^blk) (int)

Block变量和一般的C语言变量完全相同,可作为以下用途使用:

1、自动变量;

2、函数参数;

3、静态(局部)变量;

4、静态全局变量;

5、全局变量;

2、截获自动变量值

demo如下:

int i = 10;

NSString *str = @"hello";

void (^blk) (void) = ^{

    NSLog(@"str = %@, i = %d", str, i);

};

str = @"I'm not ok";

i = 11;

blk();

NSLog(@"end");

最后打印的日志如下:


从上面的日志可以看出:Block语法使用的是之前定义时的自动变量的值,也就是截获自动变量的值,保存起来,在执行时使用。即使在block定义和执行期间修改过这些自动变量的值,也不会影响,它还是执行之前定义时所截获的自动变量值。

这就是自动变量值的截获。

3、__block说明符

int i = 10;

NSString *str = @"hello";

void (^blk) (void) = ^{

    i = 12;

    NSLog(@"str = %@, i = %d", str, i);

};

str = @"I'm not ok";

i = 11;

blk();

NSLog(@"end");

这个时候,i = 12会报错:

Variable is not assignable (missing __block type specifier)

如果将i声明为__block int i = 10;,就可以实现在block中对i进行赋值。

这种变量称为__block变量。

4、Block循环引用

避免循环引用的方法有三种:

1、使用__block

2、使用__weak

3、使用__unsafe_unretained

使用__block修饰符的优点:

1、可以动态的控制对象的持有周期;(在执行block时,可动态的决定是都将nil或者其他对象赋值给__block变量)

2、在ARC和MRC都可以使用;

3、可以修饰对象,也可以修饰基本数据类型;

使用__block修饰符的缺点:

1、为了避免循环引用,必须执行Block;如果只执行了Block语法,却不执行Block的使用时,无法避免循环使用。

__weak修饰的自动变量:不能在Block中被赋值;只能修饰对象,不能修饰基本数据类型。

unsafe_unretained是在iOS4以及OS X Snow Leopard的环境下,也就是不能使用weak的环境下使用

5、copy/release

ARC无效时,

Block从栈复制到堆,是通过copy实例方法实现;

手动释放Block,通过release实例方法来来释放;

在堆上,可通过retain实例方法持有;

而在栈上,使用retain方法持有是无效的;

因此推荐使用copy实例方法来持有Block,copy方法可实现将Block从栈复制到堆上。

默认情况下,Block创建时是在栈上的。

ARC无效时,__block可以被用来避免Block的循环使用。

因为,当Block从栈复制到堆上时,如果Block中使用的自动变量,有block说明符,那么就不会被retain。如果Block中使用的自动变量,没有block说明符,那么就会被retain。

注意:__block修饰符在ARC有效和无效时,区别很大,因此使用需注意。

6、为什么要选用copy来修饰Block?

首先,Block也是OC对象。

Block一共有三种类型:

1)、全局Block( _NSGlobalBlock):设置在程序的数据区(.data区);

2)、栈中的Block( _NSStackBlock):设置在栈上的;

3)、堆中的Block( _NSMallocBlock):设置在由malloc函数分配的内存块(堆)中。

1)、全局Block对象

有两种情况:

(1)在记述全局变量的地方存在Block语法:因为在使用全局变量的地方不能使用自动变量,所以不存在对自动变量的截获,因此Block语法的内容也不会依赖于执行时的状态,就可以设置在与全局变量相同的数据区域,因此成为全局Block对象;(不截获)

(2)Block语法中的表达式,可能会截获自动变量的值,但是只要不使用截获的自动变量,这样的Block也是全局Block;(截获但不使用)

2)、栈中的Block

除了上面两种情况之外生成的Block都是_NSStackBlock对象,设置在栈上。

3)、堆中的Block

配置在全局变量上的Block,从变量的作用域外也可以通过指针安全的使用。

设置在栈上的Block,如果其所属的变量的作用域结束,这个Block也会被废弃。block变量也是配置在栈上的,如果其所属的变量的作用域结束,这个block变量也会被废弃。

Block提供了将Block和__block变量从栈上复制到堆上的方法来解决问题,这样“即使Block语法记述的变量作用域结束,堆上的Block也可以继续存在”。

在ARC有效时,编译器大多数情况下会恰当的进行判断,自动生成将Block从栈上复制到堆上的代码。比如,将Block作为函数返回值返回时,编译器会自动生成复制到堆上的代码。

但是有些情况下,需要手动的使用copy方法生成代码,来将Block从栈上复制到堆上。

这些不能自动生成复制代码的情况有:

1、通过方法或函数的参数传递Block时,需要手动复制。

但是如果在方法或者函数中适当的复制了传递过来的参数,就不必在调用之前手动复制了。

比如在Cocoa框架的方法名中含有usingBlock的方法(如NSArray类的enumerateObjectsUsingBlock方法),再比如Grand Central Dispatch的API(如dispatch_async函数)。

如果不想判断这些情况,可以在所有情况下都进行copy,但是Block从栈上复制到堆上是非常消耗CPU的。

对于已经在堆上的Block或者全局Block调用copy方法,不会引起任何问题。

对于全局的Block进行copy时,什么也不做;

对于堆上的Block进行copy时,Block的引用计数加1.

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

推荐阅读更多精彩内容