1. Block语法

Block语法完整形式如下:

^void (int event) {printf("buttonId:%d event=%d\n", i, event);
}

完整形式的Block语法与一般的C语言函数定义相比,仅有两点不同。

  1. 没有函数名。
  2. 带有“^”(插入记号)。

因为OS X、iOS应用程序会大量使用Block,所以插入“^”记号方便查找。

以下为Block语法的BN范式。

Block_literal_Expression ::= ^block_decl Compound_statement_body
block_decl ::=
block_decl ::= parameter_list
block_decl ::= type_expression

即便此前不了解BN范式,通过说明也能有个概念。

^ 返回值类型 参数列表 表达式

省略返回值类型

^ 参数列表 表达式

省略返回值类型时,Block语法将按照return语句的类型返回。如果表达式中有多个return语句,所以return语句的类型必须一致。

省略参数列表

^ 返回值类型 表达式

如果不使用参数,可省略。

省略返回值和参数列表

^ 表达式

2. Block类型变量

在定义C语言函数时,就可以将所定义的函数的地址赋给函数指针类型变量中。

int func(int count)
{return count + 1;
}
int (*funcptr)(int) = &func;

同样的,在Block语法下,可将Block语法赋值给声明为Block类型的变量中。即源代码中一旦使用Block语法就相当于生成了可赋值给Block类型变量的“值”。在有关Block语法的文档中,“Block”即指源代码中的Block语法也指由Block语法所生成的值。

声明Block变量的示例:

int (^bik)(int);

该Block类型变量与一般C语言函数变量完全相同,可作为以下用于使用。

  • 自动变量
  • 函数参数
  • 静态变量
  • 静态全局变量
  • 全局变量

使用Block语法,将Block赋值为Block变量。

int (^blk)(int) = ^(int count){return count + 1};

有“^”开始的Block语法生成的Block被赋值给变量blk中。因为与通常的变量相同,所以当然也可以有Block类型变量赋值给Block类型变量。

int (^bilk1)(int) = blk;
int (^blk2)(int);blk2 = blk1;

在函数参数中使用Block类型变量可以向函数传递Block。

void func(int (^blk)(int))
{...
}

在返回值类型中指定Block类型,可以将Block作为函数的返回值。

int (^func())(int)
{return ^(int count){return count + 1};
}

但是在参数和函数返回值中使用Block类型变量极为复杂。这时,我们可以使用typedef来解决该问题。

typedef int (^blk_t)(int);

如上所示,通过使用typedef可声明“blk_t”类型变量。

void func(blk_t blk)
{...
}blk_t func()
{return ^(int count){return count + 1};
}

另外,将赋值给Block的类型变量中的Block方法像C语言通常的函数调用那样使用,这种方法与使用函数指针类型变量调用函数的方法几乎完全相同。
变量funcptr为函数指针类型时,像下面这样调用函数指针类型变量:

int result = (*funcptr)(10);

变量blk为Block类型的情况下,这样调用Block类型变量:

int result = blk(10);

通过Block类型变量调用Block与C语言通常的函数调用没有区别。在函数参数中使用Block类型变量并在函数中执行Block的例子如下:

int func(blk_t elk, int rate) {return blk(rate);
}

在Objective-C方法中:

- (int) methodUsingBlock:(blk_t) rate:(int)rate
{return blk(rase);
}

Block类型变量可完全像通常的C语言变量一样使用,因此也可以使用指向Block类型变量的指针,即Block的指针类型变量。

typedef int (^blk_t)(int);blk_t blk = ^(int count){return count + 1};blk_t *blkptr = &blk;(*blkptr)(10);

3. 截获自动变量

通过Block语法和Block类型变量的说明,我们已经理解了“带有自动变量值的匿名函数”中的匿名函数。而带有自动变量是什么呢?“带有自动变量值”在Block中表现为“截取自动变量值”。截取自动变量值的实例如下:

int main()
{int day = 256;int val = 10;const char *fmt = "val = %d\n";void (^blk)(void) = ^(printf(fat, val));val = 2;fmt = "These values were changed. val = %d\n";blk();return 0;
}

该源代码中,Block语法的表达式使用的是它之前声明的自动变量fmt和val。Blocks中,Block表达式截获所使用的自动变量的值,即保存该自动变量的值,即保存该自动变量的瞬间值。因为Block表达式保存了自动变量的值,所以在执行Block语法后,即便改写Block中使用的自动变量的值也不会影响Block执行时自动变量的值。该源代码就在Block改写后改写了Block中自动变量val和fmt。
执行结果:

val = 10

这就是自动变量的截获。

4. __block 说明符

实际上,自动变量值截获只能保存执行Block语法瞬间的值。保存后就不能改写该值。若想在Block语法的表达式中将值赋给Block语法外声明的自动变量,需要在该自动变量上附加__block说明符。我们称这种变量为__block变量。

__block int val = 0;void (^blk)(void) = ^{val = 1};blk();printf("val = %d\n", val);

该代码执行结果:

val = 1

5. 截获的自动变量

截获Objective-C对象,调用变更该对象的方法不会产生编译错误。

id array = [[NSMutableArray alloc] init];void (^blk)(void) = ^{id obj == [[NSObject alloc] init];[array addObject:obj];
};

这是没有问题的,而向截获的变量array赋值则会产生编译错误。该源代码中截获的变量值为NSMutableArray类对象用的结构体指针。

这种情况下需要给截获的自动变量附加__block说明符。

__block id array = [[NSMutableArray alloc] init];void (^blk)(void) = ^{array = [[NSMutableArray alloc] init];
};

另外,在使用C语言数组时必须小心使用其指针。只是使用C语言的字符串字面量数组,而并没有向截获的自动变量赋值,因此看似没有任何问题。但实际上会产生编译错误。

const char text[] = "hello";void (^blk)(void) = ^{printf("%c\n", text[2]);
};
error: cannot refer to declaration with an array type inside blockprintf("%c\n", text[2]);
note: delared hereconst char text[] = "hello";^

这是因为在现在的Block中,截获的自动变量的方法并没有实现对C语言数组的截获。这时,使用指针可以解决该问题。

const char *text = "hello";
void (^blk)(void) = ^{printf("%c\n", text[2]);
};

【OC】Blocks模式相关推荐

  1. 技嘉 b360m d3h-cf efi_技嘉Geforce RTX 3080 GAMING OC 10G评测:性能入魔,方为魔鹰_显卡...

    2020-10-23 14:54:131点赞2收藏1评论 想攒一台电竞主机.家用主机.酷炫主机无从下手?想省钱又怕性能不达标?值得买帮你打造定制化DIY装机工具,自助全网比价装机,提供最适合的搭配方案 ...

  2. Art Blocks:生成艺术的自动售货机

    撰文:程天一 来源:海外独角兽 代码和软件已经占据了我们的生活,但是使用代码创作出的生成艺术在过去很多年中始终被低估.2021 年夏天开始的 NFT 和 Art Blocks 热潮改变了这一点. Ar ...

  3. STM8单片机定时器驱动的深度解析

    上一节给大家介绍了基于标准库STM8单片机GPIO的驱动,本节课主要给大家介绍一下STM8定时器的驱动. 我们先打开STM8L10x单片机的规格书,简单的了解一下STM8L10X单片机的定时器功能. ...

  4. DRV8301的使用

    特点 电压6V到60V 1.7A栅极驱动电流,2.3A吸收电流 支持3.3V和5V接口 集成一个buck电源,可调节输出电压和开关频率,可对外提供1.5A电流 死区时间可调整.过流保护可调整.PVDD ...

  5. 微星主板超频_内存超频能力依旧拔群!微星MEG Z490 ACE主板评测

    一.前言:内存超频首选的新板子来了 一直以来,微星主板都以强悍的内存超频能力而著称,而高频内存对于许多游戏带来的提升都是肉眼可见. 随着全新Intel 10代酷睿处理器的上市,微星的MEG系列的Z49 ...

  6. 开源商业化未来究竟如何?国际开源圈网红这样说

    [CSDN 编者按]Joseph Jacks 是国际开源圈网红,他作为 OCS 峰会创始人.早年KubeCon的发起人.CNCF 顾问,本文是他回顾这些年来他在开源的全部经历,他表示在未来几十年仍投身 ...

  7. Reason Studios Reason 12 v12.2.5 WiN 音乐制作软件和机架插件

    Reason Studios Reason 12是一个带有模块化环境.无限音轨.软合成器.虚拟乐器.效果器.播放器设备.音高编辑.MIDI 输出和机架扩展的 DAW 软件和机架插件. Reason 1 ...

  8. 华南主板超频设置图解_实用至上,微星B550 TOMAHAWK主板开箱拆解+测试

    就在上周,AMD发布了全新的5000系列zen3处理器,优化了频率和缓存设计让管家十分期待,因此管家入手了一张来自MSI微星的B550 TOMAHAWK主板,坐等月底新CPU开卖,也顺便做个开箱试玩给 ...

  9. 无法定位程序输入点 except_S120变频器的基本定位功能详解,建议收藏

    一.概述S120 有两种形式: 用于多轴系统的 DC/AC 装置 用于单轴系统的 AC/AC 装置 这两种形式的 Firmware V2.4 及以上版本都已具备基本定位功能.当前V2.4 版本的 S1 ...

最新文章

  1. mysql系统云结构图_腾讯梁定安解密织云系统!(附架构图)
  2. Yocto的使用实例
  3. [crypto]-50-base64_encode和base64_decode的C语言实现
  4. 使用three.js实现炫酷的酸性风格3D页面
  5. BZOJ3862Little Devil I——树链剖分+线段树
  6. cmake-debug和release模式
  7. matlab机械臂工作空间代码_【ROS-Moveit!】机械臂控制探索(3)——基于python的API示例代码分析...
  8. c# String 前面不足位数补零的方法 (转贴)
  9. Apache Common-cli简单使用
  10. MVC Json方法里的一个坑
  11. 已加密的PDF怎么解密?只要学会这两招即可轻松解密
  12. 【3dmax千千问】初学3dmax插件神器第21课:3dmax渲染教程|疯狂模渲大师怎么深度讲解VRAY渲染器的用法呢?室内设计师怎么用VRAY渲染3dmax效果图的模型?
  13. 时间管理四象限法则该如何理解
  14. 不会真有人觉得在广州、深圳这样的城市月薪过万很容易吧
  15. 电脑qq游戏程序更改计算机,电脑怎么把qq游戏快捷到桌面
  16. 【iOS开发】生成Appicon图标、为iOS应用添加图标
  17. linux查看目录是不是btrfs,Linux之btrfs详解2015082901
  18. mysql 联合索引 abc_ABC联合索引生效问题(整理笔记!!!)
  19. 淘宝x-sign, x-mini-wua, x-sgext, x-umt挂unidbg分析
  20. CCF CSP 点亮数字人生(记忆化搜索+拓扑排序判环)

热门文章

  1. 计算机视觉——相机定位
  2. (附源码)Python云顶之弈数据分析系统 毕业设计451545
  3. 程序员怎么提高英语阅读水平?
  4. linux安装和使用docker教程
  5. DDR2/3进阶实验测试篇
  6. telnet ip地址报接口23连接失败。
  7. 端口渗透—23端口Telnet
  8. c++ notify_one()和notify_all()
  9. excel-vba组内离均差
  10. 组网技术—VLANTRUNKVTP