本文来源于 ParseBlog 的其中一篇博文 《Objective-C Blocks Quiz》

如果您觉得我的博客对您有帮助,请通过关注我的新浪微博  MicroCai 支持我,谢谢!


你想知道Objective-C中blocks是怎么工作的吗?那么让我们通过几个测试题来了解下吧。 
本文所有的例子都经过以下版本的LLVM检验过:

 
  1. Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
  2. Target: x86_64-apple-darwin11.4.2
  3. Thread model: posix
 

Example A

 
  1. void exampleA() {
  2. char a = 'A';
  3. ^{
  4. printf("%c\n", a);
  5. }();
  6. }
  1. always works ?
  2. only works with ARC ?
  3. only works without ARC ?
  4. never works ?
 

Example B

 
  1. void exampleB_addBlockToArray(NSMutableArray *array) {
  2. char b = 'B';
  3. [array addObject:^{
  4. printf("%c\n", b);
  5. }];
  6. }
  7. void exampleB() {
  8. NSMutableArray *array = [NSMutableArray array];
  9. exampleB_addBlockToArray(array);
  10. void (^block)() = [array objectAtIndex:0];
  11. block();
  12. }
  1. always works ?
  2. only works with ARC ?
  3. only works without ARC ?
  4. never works ?
 

Example C

 
  1. void exampleC_addBlockToArray(NSMutableArray *array) {
  2. [array addObject:^{
  3. printf("C\n");
  4. }];
  5. }
  6. void exampleC() {
  7. NSMutableArray *array = [NSMutableArray array];
  8. exampleC_addBlockToArray(array);
  9. void (^block)() = [array objectAtIndex:0];
  10. block();
  11. }
  1. always works ?
  2. only works with ARC ?
  3. only works without ARC ?
  4. never works ?
 

Example D

 
  1. typedef void (^dBlock)();
  2. dBlock exampleD_getBlock() {
  3. char d = 'D';
  4. return ^{
  5. printf("%c\n", d);
  6. };
  7. }
  8. void exampleD() {
  9. exampleD_getBlock()();
  10. }
  1. always works ?
  2. only works with ARC ?
  3. only works without ARC ?
  4. never works ?
 

Example E

 
  1. typedef void (^eBlock)();
  2. eBlock exampleE_getBlock() {
  3. char e = 'E';
  4. void (^block)() = ^{
  5. printf("%c\n", e);
  6. };
  7. return block;
  8. }
  9. void exampleE() {
  10. eBlock block = exampleE_getBlock();
  11. block();
  12. }
  1. always works ?
  2. only works with ARC ?
  3. only works without ARC ?
  4. 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 小测验的更多相关文章

  1. 来试试这个来自静态代码分析工具PVS Studio提供C++的小测验吧

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:来试试这个来自静态代码分析工具PVS Studio提供C++的小测验吧.

  2. Java web 小测验

    题目要求: 1登录账号:要求由6到12位字母.数字.下划线组成,只有字母可以开头:(1分) 2登录密码:要求显示“• ”或“*”表示输入位数,密码要求八位以上字母.数字组成.(1分) 3性别:要求用单 ...

  3. BZOJ4635 : 数论小测验

    第一问: 设$a[i]$表示使用$[1,i]$的数字$n$次形成的数组里有多少个$\gcd=1$. 考虑容斥,则$a[i]=i^n-\sum_{j=2}^i a[\lfloor\frac{i}{j}\ ...

  4. oracle12c数据库第一周小测验

    一.单选题(共4题,30.4分) 1 (  )是位于用户与操作系统之间的一层数据管理软件.数据库在建立.使用和维护时由其统一管理.统一控制.   A. A.DBMS B. B.DB C. C.DBS ...

  5. JS小测验

    1.编写一个方法method(),判断一个数能否同时被3和5整除 <div class="one" onClick="method()"> func ...

  6. jQuery小测验

    1.在div元素中,包含了一个<span>元素,通过has选择器获取<div>元素中的<span>元素的语法是? 提示使用has() $(div:has(span) ...

  7. 【OCP、OCM、高可用等】小麦苗课堂网络班招生简章(从入门到专家)--课程大纲

    [OCP.OCM.高可用等]小麦苗课堂网络班招生简章(从入门到专家)--课程大纲 小麦苗信息 我的个人信息 网名:小麦苗 QQ:646634621 QQ群:618766405 我的博客:http:// ...

  8. 3-11 《Ruby元编程》第4章block块 3-12

    第4章代码块blocks 基础知识 作用域:用代码块携带variables through scopes 通过传递block给instance_eval方法来控制作用域. 把block转换为Proc, ...

  9. 贴心小技能——纯CSS实现的帮助提示

    1. 新技能传授---哒哒哒哒 我们经常会接到这样的小需求,鼠标放在某个位置实现一段小提示. 你还在用js实现这样一个小功能,你就太out了,来看看我们用纯CSS打造的帮助提示. 2. html &l ...

随机推荐

  1. 接口测试:如何定位BUG的产生原因

    转自公众号<QA之道> 我们从在日常功能测试过程中对UI的每一次操作说白了就是对一个或者多个接口的一次调用,接口的返回的内容(移动端一般为json)经过前端代码的处理最终展示在页面上.ht ...

  2. iOS根据网络图片的size大小设置UIImageView的大小

    有时候在设置UIImageView的大小时候需要根据UIimage的长宽比来自动设置,不让图片原比例失真. 如果是从本地获取到的图片,[UIImage imageNamed:@"" ...

  3. ES 6 : 变量的解构赋值

    1. 数组的解构赋值 [ 基本用法 ] 按照一定的模式从数组或者对象中取值,对变量进行赋值的过程称为解构. 以前,为变量赋值只能直接指定值: 而ES 6 允许写成下面这样: 上面的代码表示,可以从数组 ...

  4. Base64encode

    一直以来Base64的加密解密都是使用sun.misc包下的BASE64Encoder及BASE64Decoder的sun.misc.BASE64Encoder/BASE64Decoder类.这个类是 ...

  5. 前端tab页实例

    <div class="tabbable"> <ul class="nav nav-tabs padding-16"> <c:fo ...

  6. Oracle客户端的安装

    首先Orcale的安装应该是很简单的,安装不好只是部熟悉,在其中遇见的一些问题记录下来,如果以后忘记了还可以看看. 首先最大的问题是安装客户端的时候要安装32位的,不管你的操作系统是32位还是64位的 ...

  7. jsp/servlet中的编码问题

    首先声明以下只是我个人的看法,有部分观点与网上人云亦云的观点不一样,不过凡事必恭亲,我还是相信自己测试的结果 推荐一个很好地URL编码详解http://www.ruanyifeng.com/blog/ ...

  8. SAP HANA 能做什么

    HANA不是一个数据仓库,而是一个平台,在这个平台之上用户可以构建数据仓库或集市.报表和仪表盘等. HANA能做的,首先是作为内存数据库,提供数据插入.修改和高效的查询功能. 其次,作为一个平台,在H ...

  9. Delphi关键词

    学习的东西越来越多难免会忘记以前的知识,即使是你的大脑很发达也不见得能记得所有的东西,单词,所以做做笔记写写小抄是一个很好的习惯,到需要的时候来翻翻看看,当然个人的作小抄的习惯也不尽相同,这里我自己做 ...

  10. linux基础概念

    linux的哲学思想 一切皆文件:把几乎所有资源,包括硬件设备都组织为文件格式 由众多单一目的小程序组成:一个程序只实现一个功能,通过组合小程序完成复杂任务 尽量避免跟用户交互:实现脚本编程,以自动完 ...