[译] Block 小测验
本文来源于 ParseBlog 的其中一篇博文 《Objective-C Blocks Quiz》
如果您觉得我的博客对您有帮助,请通过关注我的新浪微博 MicroCai 支持我,谢谢!
你想知道Objective-C中blocks是怎么工作的吗?那么让我们通过几个测试题来了解下吧。
本文所有的例子都经过以下版本的LLVM检验过:
Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin11.4.2
Thread model: posix
Example A
void exampleA() {
char a = 'A';
^{
printf("%c\n", a);
}();
}
- always works ?
- only works with ARC ?
- only works without ARC ?
- never works ?
Example B
void exampleB_addBlockToArray(NSMutableArray *array) {
char b = 'B';
[array addObject:^{
printf("%c\n", b);
}];
}
void exampleB() {
NSMutableArray *array = [NSMutableArray array];
exampleB_addBlockToArray(array);
void (^block)() = [array objectAtIndex:0];
block();
}
- always works ?
- only works with ARC ?
- only works without ARC ?
- never works ?
Example C
void exampleC_addBlockToArray(NSMutableArray *array) {
[array addObject:^{
printf("C\n");
}];
}
void exampleC() {
NSMutableArray *array = [NSMutableArray array];
exampleC_addBlockToArray(array);
void (^block)() = [array objectAtIndex:0];
block();
}
- always works ?
- only works with ARC ?
- only works without ARC ?
- never works ?
Example D
typedef void (^dBlock)();
dBlock exampleD_getBlock() {
char d = 'D';
return ^{
printf("%c\n", d);
};
}
void exampleD() {
exampleD_getBlock()();
}
- always works ?
- only works with ARC ?
- only works without ARC ?
- never works ?
Example E
typedef void (^eBlock)();
eBlock exampleE_getBlock() {
char e = 'E';
void (^block)() = ^{
printf("%c\n", e);
};
return block;
}
void exampleE() {
eBlock block = exampleE_getBlock();
block();
}
- always works ?
- only works with ARC ?
- only works without ARC ?
- never works ?
解析
Example A: always works
不管在 ARC 还是 MRC 下,不论 block 存放在 stack 还是 heap 内存中,当example A 被调用时,block 仍然有效,都能正常执行.
Example B: only works with ARC
在 MRC 下,exampleB_addBlockToArray 中的 block 是 NSStackBlock 类型,存放在stack内存中。当执行 exampleB 时,stack 内存被释放,block 失效.
在 ARC 下,block 是 autoreleased NSMallocBlock 类型,存放在 heap 内存中,所以 Exmaple B only works with ARC.
Example C: always works
当 block 不需要从外部获取变量时,它不需要在 runtime 设置任何状态。此时,block 被编译成 NSGlobalBlock 类型,放在内存 data 段,就像 C 函数一样,属于代码的一部分,所以 always works.
Example D: only works with ARC
这题有点类似于 Example B. 在 MRC 下,exampleD_getBlock 中的block 会被创建在 stack 内存中,当函数返回时,block马上失效。鉴于本题的错误实在太明显,编译器在编译时,就会抛出错误 error: returning block that lives on the local stack.
而在 ARC 下,block 会被编译成 autoreleased NSMallocBlock 类型,存放于 heap 内存中。
所以 only works with ARC.
Example E: only works with ARC
本题类似于 Example D,区别在于本题代码不会出现编译错误,而是在运行时才会崩溃。更槽糕的是,如果你关闭了编译器优化选项,代码运行正常,而无法发现这个隐藏的bug。
而在 ARC 下,block 会被编译成 autoreleased NSMallocBlock 类型,存放于 heap 内存中。
所以 only works with ARC.
总结
以上这么多例子告诉我们什么?告诉我们要使用ARC!在ARC下,block总能正确运行。如果你不用ARC,最好能保证在 stack 内存中声明定义的block,能够拷贝到heap内存,保证block的正常运行。
当然,事情并不是这么简单,看苹果官方文档
Blocks “just work” when you pass blocks up the stack in ARC mode, such as in a return. You don’t have to call Block Copy any more. You still need to use [^{} copy] when passing “down” the stack into arrayWithObjects: and other methods that do a retain.
[译] Block 小测验的更多相关文章
- 来试试这个来自静态代码分析工具PVS Studio提供C++的小测验吧
博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:来试试这个来自静态代码分析工具PVS Studio提供C++的小测验吧.
- Java web 小测验
题目要求: 1登录账号:要求由6到12位字母.数字.下划线组成,只有字母可以开头:(1分) 2登录密码:要求显示“• ”或“*”表示输入位数,密码要求八位以上字母.数字组成.(1分) 3性别:要求用单 ...
- BZOJ4635 : 数论小测验
第一问: 设$a[i]$表示使用$[1,i]$的数字$n$次形成的数组里有多少个$\gcd=1$. 考虑容斥,则$a[i]=i^n-\sum_{j=2}^i a[\lfloor\frac{i}{j}\ ...
- oracle12c数据库第一周小测验
一.单选题(共4题,30.4分) 1 ( )是位于用户与操作系统之间的一层数据管理软件.数据库在建立.使用和维护时由其统一管理.统一控制. A. A.DBMS B. B.DB C. C.DBS ...
- JS小测验
1.编写一个方法method(),判断一个数能否同时被3和5整除 <div class="one" onClick="method()"> func ...
- jQuery小测验
1.在div元素中,包含了一个<span>元素,通过has选择器获取<div>元素中的<span>元素的语法是? 提示使用has() $(div:has(span) ...
- 【OCP、OCM、高可用等】小麦苗课堂网络班招生简章(从入门到专家)--课程大纲
[OCP.OCM.高可用等]小麦苗课堂网络班招生简章(从入门到专家)--课程大纲 小麦苗信息 我的个人信息 网名:小麦苗 QQ:646634621 QQ群:618766405 我的博客:http:// ...
- 3-11 《Ruby元编程》第4章block块 3-12
第4章代码块blocks 基础知识 作用域:用代码块携带variables through scopes 通过传递block给instance_eval方法来控制作用域. 把block转换为Proc, ...
- 贴心小技能——纯CSS实现的帮助提示
1. 新技能传授---哒哒哒哒 我们经常会接到这样的小需求,鼠标放在某个位置实现一段小提示. 你还在用js实现这样一个小功能,你就太out了,来看看我们用纯CSS打造的帮助提示. 2. html &l ...
随机推荐
- SVN版本控制的使用
下面说一说本人对SVN工具使用的理解: SVN就是一个工具,一个用来便于多人(或说团队)开发代码的版本控制工具,我们可以用它很好的把多个程序员开发出来的代码统一起来,并且保证在这个工程中不出现任何差错 ...
- 解决vs2013下创建的python文件,到其他平台(如linux)下中文乱码(或运行时报SyntaxError: (unicode error) 'utf-8' codec can't decode byte...)
Vs2013中创建python文件,在文件中没输入中文时,编码为utf-8的,如图 接着,在里面输入几行中文后,再次用notepad++查看其编码如下,在vs下运行也报错(用cmd运行就不会): 根据 ...
- 第 2 章 Node.js 中的交互式运行环境 —— REPL
本章内容包括: 如何使用REPL运行环境以及如何在该运行环境中测试各种JavaScript表达式. 如何定义并启动REPL运行环境. Node.js 框架中为REPL运行环境提供了哪些命令以及这些命令 ...
- out和ref之间的区别
首先:两者都是按引用传递的,使用后都将改变原来参数的数值. 其次:ref可以把参数的数值传递进函数,但是out是要把参数清空,就是说你无法把一个数值从out传递进去的,out进去后,参数的数值为空,所 ...
- 面试题-Java基础-异常部分
1.Java中的两种异常类型是什么?他们有什么区别? Java中有两种异常:受检查的(checked)异常和不受检查的(unchecked)异常.不受检查的异常不需要在方法或者是构造函数上声明,就算方 ...
- 搭建gitbook环境
1.官网下载安装nodejs,安装完成后使用终端输入node -v,用cmd命令窗口查看是否安装成功:如下图所示: 2.在cmd命令窗口中输入:npm install -g cnpm -registr ...
- redis11--java_jedis-test
使用Java开发项目的时候使用Redis的话,目前有一些开源API可以使用.最常用的就是jedis,它提供了许多基于Java的对象和方法来调用Redis的指令.jedis的jar包下载地址http:/ ...
- android判断文件是否是图片文件的方法
判断一个文件是否是图片文件的方法,采用BitmapFactory去decode然后根据返回的Options参数来确定: public static boolean isImageFile(String ...
- Web多客户端单点登录
一 数据库 除了用户表之外,新建一个外联表<用户票据表> fdUsTiUserID,fdUsTiType,fdUsTiTicket 分别对应用户ID,客户端类型(PC,mobile) 票 ...
- UITableView简单使用
在iOS开发中UITableView可以说是使用最广泛的控件,我们平时使用的软件中到处都可以看到它的影子,类似于微信.QQ.新浪微博等软件基本上随处都是UITableView.当然它的广泛使用自然离不 ...