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++, ...
随机推荐
- Image Processing and Analysis_15_Image Registration:a survey of image registration techniques——1992
此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...
- GVIM、VIM
全世界最好的编辑器VIM之Windows配置篇 Highlight all search pattern matches Top 10 things Vi user need to know abou ...
- 库克谈新iPhone不支持5G的理由,学习一下如何高手怎么应答
库克谈新iPhone不支持5G的理由 投递人 itwriter 发布于 2019-09-12 08:41 评论(14) 有1623人阅读 原文链接 [收藏] « » 9 月 12 日消息,苹果公司 C ...
- idou老师教你学Istio 23 : 如何用 Istio 实现速率限制
使用 Istio 可以很方便地实现速率限制.本文介绍了速率限制的使用场景,使用 memquota\redisquota adapter 实现速率限制的方法,通过配置 rule 实现有条件的速率限制,以 ...
- NLP学习(2)----文本分类模型
实战:https://github.com/jiangxinyang227/NLP-Project 一.简介: 1.传统的文本分类方法:[人工特征工程+浅层分类模型] (1)文本预处理: ①(中文) ...
- 深度解析Word2vec
Word2vec 本质上是一种降维操作--把词语从 one-hot encoder 形式的表示降维到 Word2vec 形式的表示,即Distributed Representation.也就是,通过 ...
- WCF Endpoint分类
WCF中可以为一个Service配置多个Endpoint 这些Endpoint的分类方法有下面3中 1.全局就一个endpoint,一个接口公开所有的方法,这适合简单的业务场景 2.将endpoint ...
- easyui-filebox上传文件或图片时选择相同文件无法触发change事件的问题
其实很简单,当选择完一个文件之后,会将文件名存放在input中的value值中,当下一次onChange之后,比对玩发现,value值没有发生变化,所以不能触发. 所以,只需要下次将value值清空就 ...
- C#中使用WCF一些常见问题及解决方案
最近在学习WCF,在这过程当中我遇到了很多的问题,简单说说我遇到的问题已经可能有效的解决方案. 1.在C#中,同一个解决方案下无法引用别的项目,引用之后会有一个警告,查看属性找不到引用的路径,这种情况 ...
- loj#6285 数列分块入门 9 ( 回 滚 )
题目 : 链接 :https://loj.ac/problem/6285 题意:给出一个长为 n的数列,以及 n个操作,操作涉及询问区间的最小众数. 思路:虽然这不是一道 回滚莫队题,就是 暴力分块 ...