`

Object-C中的块(Block)

 
阅读更多
在Object-C中,块的概念和我们熟知的函数式编程中的块概念一致,就是一个独立的逻辑处理单元,据说苹果公司为C,C++和Object-C都扩充了支持块的语法。苹果的系统是在Mac OSX10.6,iOS4.0以后支持块的。

在Object-C中,块被当做一个对象来处理,这个对象可以:

  • 有自己的局部变量
  • 可以传入参数
  • 有返回值
  • 可以访问自己定义时的上下文变量
  • 可以修改自己定义时特定的上下文变量
  • 作为参数传递给其它函数


在引入块特性之后,iOS4.0以后,很多新的API都使用了块做为参数来作为某个操作完成之后的回调。下面就来看一个例子:
- (Player *)playerAtPosition:(PlayerPosition)position {
    __block Player *player;
    [_players enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        player = obj;
        if (player.position == position)
            *stop = YES;
        else
            player = nil;
    }];
    return player;
}

这段代码的功能是在一个Dictionary中找到指定位置的玩家。代码中调用了SDK中NSDictionary类的方法:
- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block NS_AVAILABLE(10_6, 4_0);

该方法使用了一个块作为参数,表示遍历Dictionary中的每个对象时做的操作,以及什么时候停止遍历。

在例子代码中,还可以看到一个块的结构,块的定义分4部分:

  • 'void'表示返回值为空;
  • '(^)'表示接下来定义的是一个块;
  • '(id key, id obj, BOOL *stop)'表示该块接受三个参数,他们的类型分别为对象,对象和布尔类型;
  • '{…}'中的内容表示块的具体处理逻辑;

苹果官网上的图是这个样子的:

另外,代码中访问了方法的参数position,表示块可以访问自己定义时的上下文中的变量。

除此之外,块的代码中对上下文中的变量player进行了修改,因此在定义player变量时使用了'__block'关键字,表示该变量可以在块中修改。如果不加该关键字,编译器会报错“Assignment of read-only variable 'player'”。这是因为代码块内使用的是变量的副本,它是堆栈里的一个常量。这些变量在代码块中是不可改变的。。

其实,块从本质上来说是一个闭包,即其拥有代码逻辑和运行该段代码逻辑需要的变量。这一切在定义代码时就已经确定,因此,一个块在定义时访问了某个上文变量,即使之后该上下文变量发生了变化,块中仍然使用是定义时的值,可以认为块只是在定义的时候拷贝了一个变量值到自己的作用域。定义完之后,和原来的那个上下文变量就没有关系了。
NSDate *date = [NSDate date];
void (^time)(void) = ^ {
    NSLog(@"The date and time is %@", date);
};
time();
NSLog(@"The date and time is %@", date);

sleep(10);
date = [NSDate date];  
NSLog(@"The date and time is %@", date);//返回5秒后的新时间
time();//仍然返回上一次的时间

分享到:
评论

相关推荐

    Object-C语言教程&案例,要点难点,代码示例,代码解析

    Objective-C教程要点 基础语法:熟悉C语言基础是前提,Objective-C是在C语言的基础上增加了面向对象特性。...块与闭包:学习如何使用块(Block)实现闭包(Closure)功能。 多线程与并发:了解GCD(Grand Central Dispa

    oracle truncate恢复

    每列之间用空白分隔,可以只需要前四列,即块大小和是否大文件表空间可省略,块大小省略时,数据文件的默认块大小为config.txt中block_size的大小。下面是一个示例的数据: #ts #fno #rfno filename block_size ...

    kvo-block-binding:使用块观察使用KVO的Objective-C属性

    使用KVO将块绑定到属性 此仓库包含一个简单的类别,NSObject + WSObservation和一个示例项目。... block:(WSObservationBlock)block; - (WSObservationBinding*)observe:(id)object keyPath:(NSString *)keyP

    bem-object:gulp-well 的数据抽象

    level - 当前块的定义级别(级别目录的完整路径) 吸气剂 对象标识 别名 bem BEM 标识符,由block 、 elem 、 mod和val 。 应用程序接口 对象(道具) 构造 BEM 对象。 props可以是: 字符串 - 指定级别和属性:...

    SCSNotificationStore:SCSNotificationStore 是一个微型库,它为任何 Objective-C 对象提供了一种机制,可以使用块回调将其注册为通知的侦听器

    SCSNotificationStore 是一个微型库,它为任何 Objective-C 对象提供了一种机制,可以使用块回调将其注册为通知的侦听器。 为什么不直接在 NSNotificationCenter 上使用 usingBlock 方法呢? 在 ARC 下使用...

    CheckMem.pas

    Write(OutFile, BlockSize: 4, '($' + IntToHex(BlockSize, 4) + ')字节', ' - '); try Item := TObject(ObjList[I]); if PTypeInfo(Item.ClassInfo).Kind <> tkClass then { type info technique } write...

    入门学习Linux常用必会60个命令实例详解doc/txt

    -n:一般而言,mount挂上后会在/etc/mtab中写入一笔资料,在系统中没有可写入文件系统的情况下,可以用这个选项取消这个动作。 4.应用技巧 在Linux 和Unix系统上,所有文件都是作为一个大型树(以/为根)的一部分...

    S-functions x HugeBus with BusObj 作为“输入范围超出范围”的解决方法:示例显示使用 BusObjects 的“输入范围超出范围”的解决方法。-matlab开发

    为了解决这个问题,我们可以在 Bus Creators 中使用 BusObject,允许 RTW 在 C 代码中处理 Buses,而无需在外部创建一个巨大的 Block 接口。 因此一个总线被视为来自 S-Function 的唯一输出信号。

    oracle 数据库优化技术资料

    ORACLE采用一次读入多个数据块(database block)的方式优化全表扫描. b. 通过ROWID访问表 你可以采用基于ROWID的访问方式情况,提高访问表的效率, , ROWID包含了表中记录的物理位置信息..ORACLE采用索引(INDEX)...

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

    组成:表空间、段、区、块的组成层次 六、 oracle安装、卸载和启动  硬件要求 物理内存:1GB 可用物理内存:50M 交换空间大小:3.25GB 硬盘空间:10GB  安装 1. 安装程序成功下载,将会得到如下2个文件: ...

    ObjectARX for AutoCAD 2008 (32-bit)

    一整数 createTextR 写 一实数 createPline 画等宽多义线 createHatch 区域填充 insertBlock 插入图块 l 图形编辑相关函数 eraseByName 按实体的 ads_name 删除实体 eraseById 按实体的ID删除实体 changeLayerByName...

    ObjectARX for AutoCAD 2008 (64-bit)

    一整数 createTextR 写 一实数 createPline 画等宽多义线 createHatch 区域填充 insertBlock 插入图块 l 图形编辑相关函数 eraseByName 按实体的 ads_name 删除实体 eraseById 按实体的ID删除实体 changeLayerByName...

    oracle_sql性能优化

    ORACLE采用一次读入多个数据块(database block)的方式优化全表扫描. b. 通过ROWID访问表 你可以采用基于ROWID的访问方式情况,提高访问表的效率, , ROWID包含了表中记录的物理位置信息..ORACLE采用索引(INDEX)实现...

    内存管理内存管理内存管理

    要试着运行这些示例,需要先复制本代码清单,并将其粘贴到一个名为 malloc.c 的文件中。接下来,我将一次一个部分地对该清单进行解释。 在大部分操作系统中,内存分配由以下两个简单的函数来处理: void *...

    C# 俄罗斯方块游戏

    this.label1.Text="手速:"+Math.Round((double)block.BlockNum/((TimeSpan)(DateTime.Now-this.atStart)).Subtract(this.pauseTime).TotalSeconds,3)+"块/秒"; this.label2.Text="块数: "+block.BlockNum; ...

    操作系统(内存管理)

    在大部分系统语言中,比如 C 和 C++,您必须进行内存管理。本文将介绍手工的、半手工的以及自动的内存管理实践的基本概念。 追溯到在 Apple II 上进行汇编语言编程的时代,那时内存管理还不是个大问题。您实际上在...

    Oracle语句优化30个规则详解

    ORACLE采用一次读入多个数据块(database block)的方式优化全表扫描。  b. 通过ROWID访问表  你可以采用基于ROWID的访问方式情况,提高访问表的效率, ROWID包含了表中记录的物理位置信息……ORACLE采用索引(INDEX...

    Oracle优化53解

    ORACLE采用一次读入多个数据块(database block)的方式优化全表扫描。 b. 通过ROWID访问表 你可以采用基于ROWID的访问方式情况,提高访问表的效率, ROWID包含了表中记录的物理位置信息……ORACLE采用索引...

    c#学习笔记.txt

    catch (exception-declaration-2) catch-block-2 ... try try-block catch catch-block (4) fixed 防止变量被垃圾回收器重定位。 (5) lock lock 关键字将某个语句块标记为临界区。 6. 方法参数 如果为没有 ref 或 ...

Global site tag (gtag.js) - Google Analytics