enumerateKeysAndObjectsUsingBlock 的用法
block是一个有序列的指令代码块,通常在代码中间花括号括起来的objective-c代码,但是它能被传递和被分配局部变量,然后作为一个参数来传递,基本上可以把花括号中间的代码保存到数据结构里。看起来就像这样子:
NSDictionary *aDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:@"zhc",@"name", nil];
[aDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
NSLog(@"value for key %@ is %@", key, value);
if ([@"ENOUGH" isEqualToString: key]) {
*stop = YES;
}
}];
NSDictionary有一个方法叫enumerateKeysAndObjectsUsingBlock,它就一个参数就是block,这个block携带了三个参数,这将要把dictionary里面的key和value每次一组传递到block,enumerateKeysAndObjectsUsingBlock会遍历dictionary并把里面所有的key和value一组一组的展示给你,每组都会执行这个block。这其实就是传递一个block到另一个方法,在这个例子里它会带着特定参数被反复调用,直到找到一个ENOUGH的key,然后就会通过重新赋值那个BOOL *stop来停止运行,停止遍历同时停止调用block。
^表示这是一个block。在enumerateKeysAndObjectsUsingBlock之前定义一个局部变量,可以在block里使用,但它们都是只读的。
BOOL stoppedEarly = NO;
double stopValue = 53.5;
[aDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
NSLog(@"value for key %@ is %@", key, value);
if ([@"ENOUGH" isEqualToString:key] || ([value doubleValue] == stopValue)) {
*stop = YES;
stoppedEarly = YES; // ILLEGAL 违法的提示报错
}
}];
不过如果你在前面加上_block,就会变成可读写了,然后在block执行完后它会保留被赋的值。
__block BOOL stoppedEarly = NO;
double stopValue = 53.5;
[aDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
NSLog(@"value for key %@ is %@", key, value);
if ([@"ENOUGH" isEqualToString:key] || ([value doubleValue] == stopValue)) {
*stop = YES;
stoppedEarly = YES; // 可以编译通过
}
}];
在block里面用了一个实例变量,出来后也是有效的,而且不是只读的。
typedef 一个 block:
typedef double (^unary_operation_t)(double op);
这行代码的意思就是定义一个新类型,它本质上是一个block,它接受一个类型为double的参数,返回值的类型也是double的,新类型的名字叫unary_operation_t。
已经定义好了这个类型,现在用它声明一个变量,变量名叫square,接下来给它赋值:
unary_operation_t square;
square = ^(double operand) {
return operand * operand;
}
现在有了一个类型为 unary_operation_t 的变量square,怎么用呢?就像用一个C语言函数一样:
double squareOfFive = square(5.0);
把5.0作为参数传给block,5.0就是block里面的操作数,它进行平方操作,得到25。
这有一行代码可以不用typedef直接声明square:
double (^square)(double op) = ^(double op) { return op * op; };
此处的square是一个变量,而不是一个类型。
一旦定义好unary_operation_t,这种类型实际上是一个block,就可以用它进行函数声明了,把它作为函数的参数,就是声明一个参数为unary_operation_t类型的方法,比如addUnaryOperation:whichExecutesBlock:,第二个参数是block,可以用unary_operation_t来声明这个方法。首先,加入一个property:
@property (nonatomic, strong) NSMutableDictionary *unaryOperations;
它就是一个用来存储所有unaryOperations 的 dictionary,用来记录key值的dictionary。
然后实现 addUnaryOperation:whichExecutesBlock:
typedef double (^unary_operation_t)(double op);
- (void)addUnaryOperation:(NSString *)op whichExecutesBlock:(unary_operation_t)opBlock {
[self.unaryOperations setObject:opBlock forKey:op];
}
这个方法的第二个参数是一个block,unary_operation_t指明了block的类型。把block看成一个对象,通过给定的key加入到dictionary里。block用起来像类一样,实际不是,只是有些相似,不能给它传递消息,可以像安置id一样安置它们。
ARC负责block的内存管理,由于它本身并不是一个对象,它靠ARC进行内存管理,当block执行完之后,它的内存是自动释放的。
然后我们就有了一个字典,字典的key是代表操作的字符串,值是block。接着可以这么做:
- (double)performOperation:(NSString *)operation{
unary_operation_t unaryOp = [self.unaryOperations objectForKey:operation];
if (unaryOp) {
self.operand = unaryOp(self.operand);
}
}
大多数不用typedef来声明一个方法,比如
- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block;
没有返回值所以是void,注意(^),在括号中间没有其他东西,是因为没有定义type。后面就是block需要的参数,然后就是block。
block 很常见,实际上有简便方法,然后有两件事情需要去做:第一,不必去声明那些能被block里面引用的返回的type,如果它能够在block里被推断出来,比如
NSNumber *secret = [NSNumber numberWithDouble:42.0];
[brain addUnaryOperation:@"MoLtUaE" whichExecutesBlock:^(double operand) {
return operand * [secret doubleValue];
];
另外一个就是如果一个block没有参数的话,不必写这个(),比如
[UIView animateWithDuration:5.0 animations:^{ view.opacity = 0.5;}];
没有参数,没有返回值,仅仅是花括号。
enumerateKeysAndObjectsUsingBlock 的用法的更多相关文章
- Objective-C中的runtime的原理和用法
一.runtime介绍 runtime翻译就是运行时,我们称为运行时机制.在OC中最重要的体现就是消息发送机制. 1)在C语言中,程序在编译过程中就决定调用哪个函数. 2)在OC中,编译的时候不会决定 ...
- EditText 基本用法
title: EditText 基本用法 tags: EditText,编辑框,输入框 --- EditText介绍: EditText 在开发中也是经常用到的控件,也是一个比较必要的组件,可以说它是 ...
- jquery插件的用法之cookie 插件
一.使用cookie 插件 插件官方网站下载地址:http://plugins.jquery.com/cookie/ cookie 插件的用法比较简单,直接粘贴下面代码示例: //生成一个cookie ...
- Java中的Socket的用法
Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...
- [转载]C#中MessageBox.Show用法以及VB.NET中MsgBox用法
一.C#中MessageBox.Show用法 MessageBox.Show (String) 显示具有指定文本的消息框. 由 .NET Compact Framework 支持. MessageBo ...
- python enumerate 用法
A new built-in function, enumerate() , will make certain loops a bit clearer. enumerate(thing) , whe ...
- [转载]Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法总结
本文对Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法进行了详细的总结,需要的朋友可以参考下,希望对大家有所帮助. 详细解读Jquery各Ajax函数: ...
- 【JavaScript】innerHTML、innerText和outerHTML的用法区别
用法: <div id="test"> <span style="color:red">test1</span> tes ...
- chattr用法
[root@localhost tmp]# umask 0022 一.chattr用法 1.创建空文件attrtest,然后删除,提示无法删除,因为有隐藏文件 [root@localhost tmp] ...
随机推荐
- 安卓终端-Termux
Termux是一个 Android 终端模拟器以及提供 Linux 环境的应用程序.跟许多其他应用程序不同,无需 root 设备也无需进行设置.它是开箱即用的!它会自动安装好一个最基本的 Linux ...
- spring boot集成Websocket
websocket实现后台像前端主动推送消息的模式,可以减去前端的请求获取数据的模式.而后台主动推送消息一般都是要求消息回馈比较及时,同时减少前端ajax轮询请求,减少资源开销. spring boo ...
- NodeVisitor
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source ...
- netty5心跳与业务消息分发实例
继续基于我们之前的例子(参见netty5自定义私有协议实例),这次我们加上连接校验和心跳机制: 只要校验通过,客户端发送心跳和业务消息是两个不同的事件发送的,彼此互不干扰.针对以上流程,我们需要增加4 ...
- 深入学习c++--lambda函数
1. 简单使用 #include <iostream> #include <functional> using namespace std; struct Print { vo ...
- 使用ffmpeg.exe进行转码参数说明
使用ffmpeg.exe进行转码参数说明 摘自:https://blog.csdn.net/coloriy/article/details/47337641 2015年08月07日 13:04:32 ...
- while死循环
while死循环放入主线程要注意,如果处理不当可能引起界面假死,如果界面假死,可以放入子线程中(如果每个循环处理时间现对于CPU很短,则建议在本次循环结束的尾部加入Sleep以释放对CPU的占用) C ...
- ubuntu18.04手动安装二进制MySQL8.0
wget https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.13-linux-glibc2.12-x86_64.tar.xz tar xvJf ...
- web端自动化——Selenium Grid原理
利用Selenium Grid可以在不同的主机上建立主节点(hub)和分支节点(node),可以使主节点上的测试用例在不同的分支节点上运行. 对不同的节点来说,可以搭建不同的测试环境(操作系统.浏 ...
- servlet中ServletContainerInitializer的简单说明
根据官方文档到的说明 public interface ServletContainerInitializer Interface which allows a library/runtime to ...