【iOS】Blocks
Block
- Blocks概要
- 什么是Blocks?
- Block语法
- Block类型变量
- 截获自动变量值
- __block说明符
- Blocks的实现
- Block的实质
Blocks概要
什么是Blocks?
Blocks可简单概括为:
带有自动变量(局部变量)的匿名函数
在使用Blocks时,可以不声明C++类和Objective-C类,也没有使用静态变量、静态全局变量或全局变量时的问题,仅用编写C语言函数的源代码量即可使用带有自动变量值的匿名函数。
对于“带有自动变量值的匿名函数”这一概念并不仅指Blocks。它还存在于许多其他程序语言中。在计算机科学中,此概念也称为闭包(Closure)、lambda计算(λ计算)等。

Block语法
完整的Block语法与一般的C语言函数定义相比,仅有两点不同。
- 没有函数名
- 带有“^”
^:
由于OS X、iOS应用程序的源代码中将大量使用Block,所以插入该记号便于查找。
例如可写出下面形式的Block语法:
^int (int count) {return count + 1;}
当省略返回值类型时:
^(int count) {return count + 1;}
省略返回值类型时,如果表达式中与return语句就使用该返回值的类型;如果没有return语句就使用void类型;当表达式中含有多个return语句时,所有return的返回值类型必须相同。
如果不使用参数,参数列表也可省略:
^void (void) {printf("Blocks\n");}
上述代码可以省略为:
^{printf("Blocks\n");}
Block类型变量
声明block类型变量的实例如下:
int (^blk) (int);
使用block语法将Block赋值给Block类型变量:
int (^blk) (int) = ^int (int count) {return count + 1;};
由"^"开始的 Block 语法生成的 Block 被赋值给变量 blk 中。因为与通常的变量相同,所以当然也可以由Block类型变量向 Block 类型变量赋值:
int(^blk1)(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(int (^blk)(int) )
*/void func (blk_t blk) {/* 原来的记述方式
int(^func ()(int))
*/blk_t func() {
通过 Block类型变量调用Block与C语言通常的函数调用没有区别。在函数参数中使用Block类型变量并在函数中执行 Block 的例子如下:
int func(blk_t blk,int rate) {return blk (rate);
}
当然,在 Objective-C的方法中也可使用。
-(int) methodUsingBlock:(blk_t)blk rate:(int)rate {return blk (rate);
}
截获自动变量值
int main() {int dmy = 256;int val = 10;const char *fmt = "val = 号d\n";void (^b1k)(void) = ^{printf(fmt,val);};val = 2;fmt = "These values were changed. val = %d\n";blk();return 0;
}
结果是
val= 10
执行结果并不是改写后的值"These values were changed. val=2",而是执行 Block 语法时的自动变量的瞬间值。该Block语法在执行时,字符串指针"val=%d\n"被赋值到自动变量 fmt中,int 值10被赋值到自动变量 val中,因此这些值被保存(即被截获),从而在执行块时使用。
这就是自动变量值的截获。
__block说明符
实际上,自动变量值截获只能保存执行 Block 语法瞬间的值。保存后就不能改写该值。下面我们来尝试改写截获的自动变量值,看看会出现什么结果。下面的源代码中,Block 语法之前声明的自动变量 val 的值被赋予1。
int val=0
void ("blk)(void) = ^{val = 1;};
blk();
printf("val = %d\n",val);
以上为在 Block 语法外声明的给自动变量赋值的源代码。该源代码会产生编译错误。
error: variable is not assignable (missing __block type specifier)
void (^blk)(void)= ^{val = 1;};
若想在 Block 语法的表达式中将值赋给在 Block 语法外声明的自动变量,需要在该自动变量上附加 block 说明符。该源代码中,如果给自动变量声明 int val附加 block 说明符,就能实现在Block 内赋值。
_block int val = 0;
void (^blk)(void) = ^{val = 1;};
blk();
printf("val = d\n",val);
执行结果:
val =1
那么截获 Objective-C 对象,调用变更该对象的方法也会产生编译错误吗?
id array = [[NSMutableArray alloc] init];
void (^blk)(void)= ^{id obj =[[NSObject alloc] init];[array addObject:obj];
};
这样是不会出错的,但是如果是向截获的变量 array 赋值则会产生编译错误。该源代码中截获的变量值为NSMutableArray 类的对象。如果用C语言来描述,即是截获NSMutableArray 类对象用的结构体实例指针。虽然赋值给截获的自动变量 array 的操作会产生编译错误,但使用截获的值却不会有任何问题。
下面源代码向截获的自动变量进行赋值,因此会产生编译错误。
id array =[[NSMutableArray alloc] init];
void(^b1k)(void) = ^(
array =[[NSMutableArray alloc] init];
};
error: variable is not assignable(missingblock type specifier)
array = [[NSMutableArray alloc] init];
这种情况下,需要给截获的自动变量附加_block 说明符。
__block id array =[[NSMutableArray alloc] init];
void (^blk)(void) = ^{array = [[NSMutableArray alloc] init];
};
另外,在使用C语言数组时必须小心使用其指针。源代码示例如下∶
const char text[] = "hello";
void (^blk)(void) = ^{printf("%c\n", text[2]);
};
只是使用C语言的字符串字面量数组,而并没有向截获的自动变量赋值,因此看似没有问题。但实际上会产生以下编译错误∶
error; cannot refer to declaration with an array type inside block
printf("cAn",text[2]);note: declared here
const char text [] ="hello";
这是因为在现在的 Blocks 中,截获自动变量的方法并没有实现对C语言数组的截获。这时,使用指针可以解决该问题。
const char *text = "hello";
void (^blk)(void)= ^{printf("%c\n",text [2]);
}
Blocks的实现
Block的实质
Block是"带有自动变量值的匿名函数",但 Block究竟是什么呢?本节将通过Block 的实现进一步帮大家加深理解。
前几节讲的 Block 语法看上去好像很特别,但它实际上是作为极普通的C语言源代码来处理的。通过支持 Block 的编译器,含有Block 语法的源代码转换为一般C语言编译器能够处理的源代码,并作为极为普通的C 语言源代码被编译。
这不过是概念上的问题,在实际编译时无法转换成我们能够理解的源代码,但 clang(LLVM 编译器)具有转换为我们可读源代码的功能。通过"-rewrite-objc"选项就能将含有Block 语法的源代码变换为C++的源代码。说是C++,其实也仅是使用了struct结构,其本质是C语言源代码。
clang -rewrite-objc 源代码文件名
下面,我们转换 Block 语法。
int main() {void (^blk)(void) = ^{printf("Block\n");};blk();return 0;
}
此源代码的 Block 语法最为简单,它省略了返回值类型以及参数列表。该源代码通过 clang 可变换为以下形式∶
//经过clang转换后的C++代码
struct __block_impl {void *isa;int Flags;int Reserved;void *FuncPtr;
};struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};static void __main_block_func_0(struct __main_block_impl_0 *__cself {printf("Block\n");
}static struct __main_block_desc_0 {size_t reserved;size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};int main(int argc, const char * argv[]) {void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);return 0;
}
相关文章:
【iOS】Blocks
BlockBlocks概要什么是Blocks?Block语法Block类型变量截获自动变量值__block说明符Blocks的实现Block的实质Blocks概要 什么是Blocks? Blocks可简单概括为: 带有自动变量(局部变量)的匿名函数 在使用Blocks时&#x…...
Java Volatile的三大特性
本文通过学习:周阳老师-尚硅谷Java大厂面试题第二季 总结的volatile相关的笔记volatile是Java虚拟机提供的轻量级的同步机制,三大特性为:保证可见性、不保证原子性、禁止指令重排一、保证可见性import java.util.concurrent.TimeUnit;class M…...
Android Compose——一个简单的Bilibili APP
Bilibili移动端APP简介依赖效果登录效果WebView自定义TobRow的Indicator大小首页推荐LazyGridView使用Paging3热门排行榜搜索模糊搜索富文本搜索结果视频详情合集信息Coroutines进行网络请求管理,避免回调地狱添加suspendwithContextGit项目链接末简介 此Demo采用A…...
二叉树的最近公共祖先【Java实现】
题目描述 现有一棵n个结点的二叉树(结点编号为从0到n-1,根结点为0号结点),求两个指定编号结点的最近公共祖先。 注:二叉树上两个结点A、B的最近公共祖先是指:二叉树上存在的一个结点P,使得P既是…...
关闭应用程序遥测,禁止Windows收集用户信息
目录 1. 先创建还原点,防止意外 2. 界面设置 3. 服务 (1) GPEdit.msc - 本地计算机策略 - 计算机配置 - 管理模板 - Windows 组件 - 应用程序兼容性 - 关闭应用程序遥测 - 已启用 (2) GPEdit.msc - 本地计算机策略 - 计算机配置 - 管理模板 - Windows 组件 - 数…...
【备战面试】每日10道面试题打卡-Day4
本篇总结的是Java集合知识相关的面试题,后续也会更新其他相关内容 文章目录1、HashMap在JDK1.7和JDK1.8中有哪些不同?2、HashMap 的长度为什么是2的幂次方?3、HashMap的扩容操作是怎么实现的?4、HashMap是怎么解决哈希冲突的&…...
热乎的面经——初出茅庐
⭐️前言⭐️ 本篇文章记录博主与2023.03.04面试上海柯布西公司,一面所被问及的面试问题,回答答案仅供参考。 🍉欢迎点赞 👍 收藏 ⭐留言评论 📝私信必回哟😁 🍉博主将持续更新学习记录收获&am…...
数据库中各种锁汇总
本文汇总简记数据库中的各种锁。 名称英文名称定义解释悲观锁Pessimistic Lock在访问数据前先加锁,防止其他事务的并发修改数据通过获取锁来保证数据的独占性,从而避免并发修改数据带来的问题。乐观锁Optimistic Lock在修改数据时先不加锁,而…...
p76 - Python 开发-内外网收集 Socket子域名DNS
数据来源 Python 开发相关知识点: 1.开发基础环境配置说明 Windows10Pycharm 2.Python 开发学习的意义 学习相关安全工具原理 掌握自定义工具及拓展开发解决实战中无工具或手工麻烦批量化等情况 在二次开发 Bypass,日常任务,批量测试利用…...
QCC51XX--eFush Key加密
https://blog.csdn.net/weixin_42162924/article/details/125828901?spm=1001.2014.3001.5502 在开始讲eFush Key加密操作之前,说一下这个操作的作用就是将自己的固件采用硬件的方式进行加密。 操作步骤 1.创建一个txt文本文件,参考文档“Qualcomm BlueSuite v3.1.4 Release…...
nginx http模块
1.模块依赖2. 模块的初始化2.1 location的定义location的定义包含以下几种location [ | ~ | ~* | ^~ ] uri { ... } location name { ... }:表示精确匹配,只有请求的url路径与后面的字符串完全相等时,才会命中,不支持location嵌套~ÿ…...
守护进程 || 精灵进程
目录 守护进程(deamon) || 精灵进程 特点 什么是前台进程组 把自己写的服务器deamon deamon代码 守护进程(deamon) || 精灵进程 特点 01. 他的PPID是1(附件特征)02. COMMAND --- 称为进程启动的命令03…...
Zookeeper3.5.7版本——客户端命令行操作(znode 节点数据信息)
目录一、命令行语法二、znode 节点数据信息2.1、查看当前znode中所包含的内容2.2、查看当前节点详细数据2.3、节点详细数据解释一、命令行语法 命令行语法列表 命令基本语法功能描述help显示所有操作命令ls path使用 ls 命令来查看当前 znode 的子节点 [可监听]-w 监听子节点变…...
如何写好单测
1、为什么要写单测? 单测即单元测试(Unit Test),是对软件的基本组成单元进行的测试,比如函数、过程或者类的方法。其意义是: 功能自测,发现功能缺陷自我Code Review测试驱动开发促进代码重构并…...
CDH-6.3.2内置spark-2.4.0的BUG
1. 背景 公司最近在新建集群,全部采用开源的大数据框架,并且将之前使用的阿里云的所有服务进行下线,其中就涉及到了旧任务的迁移。 2. 任务 2.1. 简述 我接手到一个之前的 spark 任务,是读取阿里 LogStore 数据,然…...
SpringCloud之ElasticSearch笔记
ElasticSearch 初识ElasticSearch ElasticSearch是什么 ElasticSearch一个基于Lucene的底层的开源的分布式搜索引擎,可用来实现搜索,日志统计,分析,系统监控 正向索引和倒排索引 正向索引:逐条扫描(my…...
数字图像学笔记 —— 17. 图像退化与复原(自适应滤波之「最小二乘方滤波」)
文章目录维纳滤波的缺点约束最小二乘方滤波给一个实际例子吧维纳滤波的缺点 维纳滤波(Wiener Filter),虽然是一种非常强大的退化图像还原算法,但是从实验过程我们也发现它存在着致命的缺陷,那就是要求输入退化系统的 …...
2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写。
2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写。 答案2023-03-05: 使用 github.com/moonfdd/ffmpeg-go 库。 先启动lal流媒体服务器软件,然后再执行命令: go…...
MathType7最新版免费数学公式编辑器
话说我也算是 MathType准资深(DB)用户了,当然自从感觉用DB不好之后,我基本上已经抛弃它了,只是前不久因为个别原因又捡起来用了用,30天试用期间又比较深入的折腾了下,也算是变成半个MathType砖家,coco玛奇朵简单介绍一下这款软件:在很可能看到这儿的你还没有出生的某个年月&…...
一文带你入门angular(中)
一、angular中的dom操作原生和ViewChild两种方式以及css3动画 1.原生操作 import { Component } from angular/core;Component({selector: app-footer,templateUrl: ./footer.component.html,styleUrls: [./footer.component.scss] }) export class FooterComponent {flag: b…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
