- 浏览: 396877 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (325)
- 神经网络 (1)
- javascript (11)
- 数据结构 (2)
- 计算机图形学 (11)
- 模式识别 (1)
- 前端开发 (14)
- 机器学习 (11)
- ios开发 (50)
- Python (9)
- HTML5 (4)
- 计算机视觉 (9)
- 数字图像处理 (7)
- 架构设计 (19)
- 数据库设计 (9)
- 算法设计 (59)
- Java (37)
- 其他 (3)
- 游戏开发 (5)
- c++ (17)
- Linux (3)
- TCP/IP (2)
- Flex (41)
- 健康 (6)
- AI (2)
- 工具 (1)
- 数据挖掘 (1)
- 性能优化 (6)
- 综合 (2)
- 网络通信 (12)
- Android (2)
- UML (3)
- 软件设计 (11)
- 编程经验 (7)
- J2EE (1)
- 多媒体技术 (3)
- 数学 (7)
- php (4)
- 设计 (1)
- CS (2)
- 计算机理论 (1)
- 信息安全 (1)
最新评论
-
ahead_zhan:
good good good
flex3控件_ModuleLoader -
lonerzf:
好样的。非常感谢楼主
OpenCV视频教程整理 -
lonerzf:
好样的。谢谢~
OpenCV视频教程整理 -
coding1688:
博主说的不错,我在实现瀑布流布局时也用的masonry插件,有 ...
Javascript 瀑布流式布局及其动态效果的实现 -
snowolf:
除非玩游戏,不然没啥win的事情,或者用win的银行客户端,通 ...
macbook安装操作系统的机理分析
Block是iOS4.0+ 和Mac OS X 10.6+ 引进的对C语言的扩展,用来实现匿名函数的特性。
用维基百科的话来说,Block是Apple Inc.为C、C++以及Objective-C添加的特性,使得这些语言可以用类lambda表达式的语法来创建闭包。
用Apple文档的话来说,A block is an anonymous inline collection of code, and sometimes also called a "closure".
关于闭包,我觉得阮一峰的一句话解释简洁明了:闭包就是能够读取其它函数内部变量的函数。
这个解释用到block来也很恰当:一个函数里定义了个block,这个block可以访问该函数的内部变量。
一个简单的Block示例如下:
int (^maxBlock)(int, int) = ^(int x, int y) { return x > y ? x : y; };
如果用Python的lambda表达式来写,可以写成如下形式:
f = lambda x, y : x if x > y else y
不过由于Python自身的语言特性,在def定义的函数体中,可以很自然地再用def语句定义内嵌函数,因为这些函数本质上都是对象。
如果用BNF来表示block的上下文无关文法,大致如下:
block_expression ::= ^ block_declare block_statement
block_declare ::= block_return_type block_argument_list
block_return_type ::= return_type | 空
block_argument_list ::= argument_list | 空
/* ---------------------------------------------------------------------------------------------------- */
[1. Why block]
Block除了能够定义参数列表、返回类型外,还能够获取被定义时的词法范围内的状态(比如局部变量),并且在一定条件下(比如使用__block变量)能够修改这些状态。此外,这些可修改的状态在相同词法范围内的多个block之间是共享的,即便出了该词法范围(比如栈展开,出了作用域),仍可以继续共享或者修改这些状态。
通常来说,block都是一些简短代码片段的封装,适用作工作单元,通常用来做并发任务、遍历、以及回调。
比如我们可以在遍历NSArray时做一些事情:
- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block;
其中将stop设为YES,就跳出循环,不继续遍历了。
而在很多框架中,block越来越经常被用作回调函数,取代传统的回调方式。
用block作为回调函数,可以使得程序员在写代码更顺畅,不用中途跑到另一个地方写一个回调函数,有时还要考虑这个回调函数放在哪里比较合适。采用block,可以在调用函数时直接写后续处理代码,将其作为参数传递过去,供其任务执行结束时回调。
另一个好处,就是采用block作为回调,可以直接访问局部变量。比如我要在一批用户中修改一个用户的name,修改完成后通过回调更新对应用户的单元格UI。这时候我需要知道对应用户单元格的index,如果采用传统回调方式,要嘛需要将index带过去,回调时再回传过来;要嘛通过外部作用域记录当前操作单元格的index(这限制了一次只能修改一个用户的name);要嘛遍历找到对应用户。而使用block,则可以直接访问单元格的index。
这份文档中提到block的几种适用场合:
任务完成时回调
处理消息监听回调处理
错误回调处理
枚举回调
视图动画、变换
排序
/* ---------------------------------------------------------------------------------------------------- */
[2. About __block_impl]
Clang提供了中间代码展示的选项供我们进一步了解block的原理。
以一段很简单的代码为例:
使用-rewrite-objc选项编译:
得到一份block0.cpp文件,在这份文件中可以看到如下代码片段:
从命名可以看出这是block的实现,并且得知block在Clang编译器前端得到实现,可以生成C中间代码。很多语言都可以只实现编译器前端,生成C中间代码,然后利用现有的很多C编译器后端。
从结构体的成员可以看出,Flags、Reserved可以先略过,isa指针表明了block可以是一个NSObject,而FuncPtr指针显然是block对应的函数指针。
由此,揭开了block的神秘面纱。
不过,block相关的变量放哪里呢?上面提到block可以capture词法范围内(或者说是外层上下文、作用域)的状态,即便是出了该范围,仍然可以修改这些状态。这是如何做到的呢?
/* ---------------------------------------------------------------------------------------------------- */
[3. Implementation of a simple block]
先看一个只输出一句话的block是怎么样的。
生成中间代码,得到片段如下:
首先出现的结构体就是__main_block_impl_0,可以看出是根据所在函数(main函数)以及出现序列(第0个)进行命名的。如果是全局block,就根据变量名和出现序列进行命名。__main_block_impl_0中包含了两个成员变量和一个构造函数,成员变量分别是__block_impl结构体和描述信息Desc,之后在构造函数中初始化block的类型信息和函数指针等信息。
接着出现的是__main_block_func_0函数,即block对应的函数体。该函数接受一个__cself参数,即对应的block自身。
再下面是__main_block_desc_0结构体,其中比较有价值的信息是block大小。
最后就是main函数中对block的创建和调用,可以看出执行block就是调用一个以block自身作为参数的函数,这个函数对应着block的执行体。
这里,block的类型用_NSConcreteStackBlock来表示,表明这个block位于栈中。同样地,还有_NSConcreteMallocBlock和_NSConcreteGlobalBlock。
由于block也是NSObject,我们可以对其进行retain操作。不过在将block作为回调函数传递给底层框架时,底层框架需要对其copy一份。比方说,如果将回调block作为属性,不能用retain,而要用copy。我们通常会将block写在栈中,而需要回调时,往往回调block已经不在栈中了,使用copy属性可以将block放到堆中。或者使用Block_copy()和Block_release()。
/* ---------------------------------------------------------------------------------------------------- */
[4. Capture local variable]
再看一个访问局部变量的block是怎样的。
生成中间代码,得到片段如下:
可以看出这次的block结构体__main_block_impl_0多了个成员变量i,用来存储使用到的局部变量i(值为1024);并且此时可以看到__cself参数的作用,类似C++中的this和Objective-C的self。
如果我们尝试修改局部变量i,则会得到如下错误:
错误信息很详细,既告诉我们变量不可赋值,也提醒我们要使用__block类型标识符。
为什么不能给变量i赋值呢?
因为main函数中的局部变量i和函数__main_block_func_0不在同一个作用域中,调用过程中只是进行了值传递。当然,在上面代码中,我们可以通过指针来实现局部变量的修改。不过这是由于在调用__main_block_func_0时,main函数栈还没展开完成,变量i还在栈中。但是在很多情况下,block是作为参数传递以供后续回调执行的。通常在这些情况下,block被执行时,定义时所在的函数栈已经被展开,局部变量已经不在栈中了(block此时在哪里?),再用指针访问就……。
所以,对于auto类型的局部变量,不允许block进行修改是合理的。
发表评论
-
IVEngine —— Objective-C的Spring
2013-12-15 20:35 0背景: 只要是Java程序员,相信都听说 ... -
XCode环境变量及路径设置
2013-11-17 16:05 1731转自:http://blog.csdn.net/freedo ... -
OVGap — 沟通 Objective-C 与 Javascript
2013-11-14 15:14 775Github 地址: https://github.com ... -
IOS开发常用命令
2013-10-11 10:41 601统计代码行数 打开terminal, cd到项目根目 ... -
提高在Xcode上的工作效率
2013-08-31 11:05 1056转自:http://liuminqian.github.io ... -
把ipa包上传到AppStore
2013-08-26 21:46 892转自:http://doc.appcan.cn/dev_io ... -
iPhone应用程序中App目录结构
2013-08-26 17:30 932转自:http://blog.csdn.net/justin ... -
iOS运行回路(RunLoop)总结
2013-08-05 13:37 717转自:http://www.cocoachina.com/i ... -
Simple iPhone Keychain Access
2013-08-04 15:54 703转自:http://useyourloaf.com/b ... -
IOS媒体层
2013-07-28 15:18 806转自:http://wd397.blog.163.com/b ... -
nginx上搭建HLS流媒体服务器
2013-07-28 13:31 1349转自:http://blog.csdn.net/ ... -
Compile ffmpeg for iOS 6, support Simulator & armv7 & armv7s
2013-07-23 17:03 773转自:http://witcheryne.iteye.co ... -
UITableView 修改编辑模式下的切图
2013-07-14 21:03 1125把以下代码放在点解 “编辑” 按钮时触发的方法中。 ... -
iOS平台UDID方案比较
2013-07-09 20:27 1478转自:http://www.cocoachina.com/b ... -
25 Free iOS Design Resources
2013-05-12 19:08 518Some great designers around th ... -
谈谈iOS Animation
2013-05-07 09:39 573转自:http://geeklu.com/2012/09/a ... -
IOS文件系统的管理
2013-05-06 17:11 594转自:http://blog.csdn.net/zhuzhi ... -
iOS应用的本地缓存机制设计
2013-05-06 16:18 638参考:http://www.cnblogs.com/peng ... -
iOS并发编程指南(3)
2013-04-28 14:37 712转自:http://mobile.51cto.com/iph ... -
iOS运行回路(RunLoop)总结
2013-04-27 23:24 648转自:http://www.cocoachina.com/i ...
相关推荐
该文档简单的介绍了ios下block是的使用方法和一些小技巧
iOS的block是学习的难点和重点,熟练使用block可以达到代码的简单高效,特别是在网络的使用过程中。Block demo是一个简单易学的,可以便于学习原理。
iOS中Block的用法,举例,解析与底层原理(Block看我really足够了)
IOS block回调代码实例Demo IOS block 回调 Demo 块
源码github.com/pro648/BasicDemos-iOS/tree/master/Block 块是一个独立的代码片段,始终存在于另一个编程结构的范围内,如在一个方法的主体。块可以捕获块外变量的值,但外部对于块内发生的事情一无所知。...
iOS block使用总结 可以结合博客http://blog.csdn.net/aiyang10/article/details/49328969理解
iOSblock方法的详细学习 指针函数和block的比较 详细自定义block
把block当成属性放在单例字典中,可以帮你跨界面,在任意一个地方都可以访问到这个block,之所以上传,是因为看到很多人还在使用代理传值,觉得费时间,这个demo简单易懂,真的好用
iOS Block 的使用, 包括传值, 基本用法
iphone开发中block的详解.pages
iOS 常用block 传值
一个block回调的例子
block,对象属性,返回值
翻译的Pro Multithreading and Memory Management for iOS and OS X with ARC, Grand Central Dispatch, and Blocks中的block章节
iOS Block 的 基本使用 演示 在Controller之间传值 和 传点击相应事件
通过自己的了解详细解析 block 反向传值
一直为block回调困惑,写个小demo熟悉熟悉
是一个block传值的测试小demo
简单的实现页面简单传值 ,主要是介绍了block的逆传值 ,简单理解,易于阅读。适用于初学者。
已经拥有一年经验的你真的了解Block 代理方法吗?也许不!以前我以为自己都有上架项目,这都是太基础的东西,但今天我重新回头看了以前做的笔记,真的是书读百遍,其义自见。