Objective-C如何自己实现一个for-each语法形式
我们在用Objective-C编写程序时,很多时候会用到NSArray来作为线性列表来使用。我们在枚举这个数组所有元素的使用可以通过下列方法进行:
for(id obj in anArray)
{ }
这种方式在编程语言术语中也被称为for-each形式。在C++11以及Java 5中,上述的in使用冒号:来表示。
那么我们在Objective-C中是否可以自己定义一个类来实现for-each形式呢?当然可以!我们可以通过两种方式来实现这种简单的for-each语法形式。
1、通过继承NSEnumerator类,并且重写其- (NSArray*)allObjects方法以及- (id)nextObject方法来实现。
2、通过实现NSFastEnumeration协议,并实现其- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id*)stackbuf count:(NSUInteger)len方法。
由于NSEnumerator类比较简单,我们可以通过看下面的代码示例即可理解。但是由于Objective-C只有单继承,因此使用对NSFastEnumeration协议的实现会更加灵活。而且这里比较复杂的是countByEnumeratingWithState方法的实现。下面先对这个方法做个简单介绍。
首先,当你的类实现了NSFastEnumeration协议并实现了countByEnumeratingWithState之后,在用for-each时,这个countByEnumeratingWithState可能需要被执行多次,依赖于你所要枚举的元素个数。因此,这个方法的返回值指示了当前所要枚举的数组的元素个数,如果返回0,则说明枚举全部完成。
参数stackbuf是指向方法调用者(即消息发送者)所分配的栈空间。这个是由编译器自动分配的,一般不需要程序员自己干涉。
参数len表示栈空间分配的大小(sizeof(id) * len个字节),也就是说单次枚举最大能放多少元素。
参数state指向由编译器给我们分配好的一个NSFastEnumerationState结构体变量地址。这个参数需要我们实现中自己来设置。我们先看这个结构体的定义:
typedef struct {
unsigned long state; // 表示当前状态,初始为0
id __unsafe_unretained *itemsPtr; // 指向当前所要枚举的数组首地址
unsigned long *mutationsPtr; // 用于检测,所要枚举的对象是否发生了改变
unsigned long extra[]; // 这里可以由实现者随意存放必要的额外数据
} NSFastEnumerationState;
对于这个结构体变量,itemsPtr与mutationsPtr必须进行设置,并且不能为空,除非,此次枚举直接返回0。
下面我们通过代码示例来详细描述这两种方法的使用:
//
// main.m
// objCTest
//
// Created by Zenny Chen on 12-2-7.
// Copyright (c) 2014年 Neon Media Studio. All rights reserved.
// #import <Foundation/Foundation.h> @interface MyIterator : NSEnumerator
{
@private NSArray *mArray;
int mCurrIndex;
} @end @implementation MyIterator - (instancetype)init
{
self = [super init]; mArray = [@[@, @, @, @, @, @, @, @] retain]; return self;
} - (void)dealloc
{
if(mArray != nil)
{
[mArray release];
mArray = nil;
} [super dealloc];
} - (NSArray*)allObjects
{
return mArray;
} - (id)nextObject
{
if(mCurrIndex == [mArray count])
return nil; return [mArray objectAtIndex:mCurrIndex++];
} @end @interface MyFastIterator : NSObject<NSFastEnumeration>
{
@private NSArray *mArray;
NSNumber* mNumbers[];
} @end @implementation MyFastIterator - (instancetype)init
{
self = [super init]; // 先对mArray进行初始化
mArray = [@[@, @, @, @, @-, @-, @-, @-,
@, @, @, @, @, @, @, @,
@, @, @, @, @, @, @, @] retain]; int i = ;
for(NSNumber *num in mArray)
mNumbers[i++] = num; return self;
} - (void)dealloc
{
if(mArray != nil)
{
[mArray release];
mArray = nil;
} [super dealloc];
} - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id*)stackbuf count:(NSUInteger)len
{
// 我们用state来表示状态。状态为1返回零,说明迭代结束;若状态为0,则继续迭代
// state初始值为零
if(state->state > )
return ; // mutationsPtr不能为空,如果假定在枚举过程中不发生修改,一般指向self
state->mutationsPtr = (unsigned long*)self; // 我们将当前剩余长度放在state的extra[0]之中
NSUInteger retCount = state->extra[]; // 所要枚举的数组指针首地址;extra[1]起始值为零
state->itemsPtr = &mNumbers[state->extra[]]; // 若为零,说明这是第一次迭代
if(retCount == )
retCount = [mArray count]; // 这里需要判断当前数组长度是否超过了本次枚举所设置的最大长度
if(retCount > len)
{
// 设置extra[0],存放剩余所要枚举的元素个数
state->extra[] = retCount - len; // 设置extra[1],存放后一次枚举起始元素索引
state->extra[] += len; retCount = len;
}
else
{
// 若剩余所要枚举的元素个数小于最大限制个数,则状态变1,使得后一次迭代能直接结束
state->state++;
} // 返回这次所要枚举的数组一共含有多少元素
return retCount;
} @end int main (int argc, const char * argv[])
{
@autoreleasepool
{
// insert code here... MyIterator *it = [[MyIterator alloc] init]; NSLog(@"The elements are: ");
for(NSNumber *num in it)
printf("%ld ", [num integerValue]);
puts("\n"); [it release]; MyFastIterator *iter = [[MyFastIterator alloc] init]; NSLog(@"The elements are: "); for(NSNumber *num in iter)
{
printf("%ld ", [num integerValue]);
}
puts(""); [iter release];
} return ;
}
Objective-C如何自己实现一个for-each语法形式的更多相关文章
- Swift和Objective C关于字符串的一个小特性
一.Unicode的一个小特性 首先,Unicode规定了许多code point,每一个code point表示一个字符.如\u0033表示字符"3",\u864e表示字符&qu ...
- ABAP 通过sumbit调用另外一个程序使用job形式执行-简单例子
涉及到两个程序: ZTEST_ZUMA02 (主程序) ZTEST_ZUMA(被调用的程序,需要以后台job执行) "ztest_zuma 的代码 DATA col TYPE i VALUE ...
- 如果以一个树状的形式返回一个UIView的所有子视图
该方法也是从一个视频中看到,总觉得会有很大作用,故记录在这里. 它返回一个xml的字符串,用火狐浏览器或者其他可以格式化xml的工具打开,即可查看其层级关系. /** * 返回传入view的所有层级结 ...
- 用java实现一个简易编译器-语法解析
语法和解析树: 举个例子看看,语法解析的过程.句子:“我看到刘德华唱歌”.在计算机里,怎么用程序解析它呢.从语法上看,句子的组成是由主语,动词,和谓语从句组成,主语是“我”,动词是“看见”, 谓语从句 ...
- c语言打印一个整数的二进制形式
printf函数没有这个功能,如果想打印一个数的二进制形式,就得自己计算.下面是我看到的最简便的算法: #include <stdio.h> int main(int argc, char ...
- JAVA--可变长参数
可变长参数: 可变长参数可以接受任意个数的实参,形参实际上是一个数组. 语法形式: 方法名称(类型 参数1,类型 参数2,类型...可变长参数) *可变长参数一定是方法的最后一个参数 public v ...
- Java Web开发模式
一 Java Web开发模式的变迁 1 最初的Java web服务器端编程技术是Servlet,利用Servlet就可以开发出一个Web应用程序. 2 为了解决Servlet缺陷,SUN推出了JSP技 ...
- NLP领域的ImageNet时代到来:词嵌入「已死」,语言模型当立
http://3g.163.com/all/article/DM995J240511AQHO.html 选自the Gradient 作者:Sebastian Ruder 机器之心编译 计算机视觉领域 ...
- Java 运算符(引用和对象)
1. 算数运算符 就是+.-.*./.%.++.--这些,没什么好说的,稍微强调下自加,自减: 前缀自增自减法(++i,--i): 先进行自增或者自减运算,再进行表达式运算. 后缀自增自减法(i++, ...
随机推荐
- CSS 样式表{二}
1 选择器的优先级 选择器的优先主要考虑选择器的权重 可以将各种选择器的权重以数值来表示,数值越大,优先级越高 选择器 权重值 标签selector 1 类选择器 10 ID选择器 100 行内样式 ...
- 微软Surface低端版本将问世
平板电脑现如今已走进千家万户,其触屏的操作相比笔记本电脑更加方便,屏幕也比手机大很多,是家用玩机的首选.虽然微软也在这一领域有所发力,推出了Surface这一产品,但其高昂的售价使得其在市场上的表现并 ...
- grafana根据不同prometheus server统计数据
场景:由于采集的数据量巨大,所以部署了多台prometheus server服务器.根据业务领域分片采集,减轻prometheus server单节点的压力. 问题:grafana如何同时显示多数据源 ...
- 跟着minium官网介绍学习minium-----(三)
注意:程序运行时在微信开发者工具当前页面为主,而不是每次运行都是从home页面开始 一 获取单个元素 get_element():在当前页面查询控件, 如果匹配到多个结果, 则返回第一个匹配到的结果 ...
- Java 基础 面向对象- 成员内部类/局部内部类/举例Comparable 接口的匿名内部类
笔记: package 任务135; /**类的 内部类, *1.相当于说, 我们可以在类的内部再定义类, * 2.成员内部类: * a.是外部类的一个成员,4个修饰符:static, final , ...
- BZOJ3122 随机数生成器——BSGS
题意 链接 给定 $p,\ a,\ b, \ x_1$,现有一数列 $$x_{i+1} \equiv (ax_i + b) \ mod \ p$$ 求最小的 $i$ 满足 $x_i = t$ 分析 代 ...
- CKEditor5 输入文字时拼音和汉字同时输入问题
在使用 CKEditor5 + vue 时,出现输入文字时,拼音和文字一起输入到编辑器到问题.与之前项目中使用 ckeditor 的区别是,这次项目是在 python 架构下局部引入 ckeditor ...
- 六十.完全分布式 、 节点管理 、 NFS网关
1.安装与部署 对mapred和yarn文件进行配置 验证访问Hadoop 在六十准备好的环境下给master (nn01)主机添加ResourceManager的角色,在node1,node2, ...
- RX232串口发送
在进行工程调试的时候有时候需要对变量进行观察,SingnaTap II Logic Analyzer 只能对管脚进行观察,所以要观察内部的变量必须把内部的变量进行输出.一种方法是直接把变量定义成管脚通 ...
- SpringMVC配置 事务管理
1.确保持久层配置完毕 2.pom.xml里追加spring-tx 3.application-context.xml追加 <bean id="transactionManager&q ...