NSArray
上进行迭代的标准习语。我的代码需要适用于OS X 10.4+。NSArray
上进行迭代的标准习语。我的代码需要适用于OS X 10.4+。10.5+/iOS一般推荐使用的代码。
for (id object in array) {
// do something with object
}
这种结构用于枚举符合 NSFastEnumeration
协议的集合中的对象。这种方法具有速度优势,因为它通过单个方法调用获得多个对象的指针并将它们存储在缓冲区中,然后通过指针算术在缓冲区上推进来迭代它们。这比每次循环都调用 -objectAtIndex:
要快得多。
值得注意的是,虽然你理论上可以使用 for-in 循环遍历 NSEnumerator
,但我发现这几乎抵消了快速枚举的所有速度优势。原因是默认的 NSEnumerator
实现 -countByEnumeratingWithState:objects:count:
每次调用都只将一个对象放入缓冲区。
我向 radar://6296108
报告了这个问题(NSEnumerators 的快速枚举速度慢),但被退回不予修复。原因是快速枚举预取一组对象,如果你想要仅枚举到枚举器中的某个点(例如找到特定对象或满足条件后停止枚举),并在退出循环后继续使用相同的枚举器,那么通常情况下会跳过多个对象。
如果你需要编写适用于 OS X 10.6 / iOS 4.0 及以上版本的代码,则还可以使用基于块的 API 枚举数组和其他集合:
[array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
// do something with object
}];
你还可以使用 -enumerateObjectsWithOptions:usingBlock:
方法,并将 NSEnumerationConcurrent
和/或 NSEnumerationReverse
作为选项参数传递。
在 10.5 之前的标准方法是使用 NSEnumerator
和 while 循环,例如:
NSEnumerator *e = [array objectEnumerator];
id object;
while (object = [e nextObject]) {
// do something with object
}
我建议保持简单。绑定到数组类型是不灵活的,而使用-objectAtIndex:的所谓速度提高在10.5+上使用快速枚举时与之相比微不足道。(实际上,快速枚举在底层数据结构上使用指针算术,并消除了大部分方法调用开销。) 过早地优化从来不是一个好主意-这会导致更混乱的代码来解决一个不是您瓶颈的问题。针对OS X 10.4.x及其之前版本:
int i;
for (i = 0; i < [myArray count]; i++) {
id myArrayElement = [myArray objectAtIndex:i];
...do something useful with myArrayElement
}
对于OS X 10.5.x(或iPhone)及更高版本:
for (id myArrayElement in myArray) {
...do something useful with myArrayElement
}
for (NSUInteger i = 0, count = [myArray count]; i < count; i++)
可能是这种方法中最高效和简洁的。 - Quinn Taylor //NSArray
NSArray *arrData = @[@1,@2,@3,@4];
// 1.Classical
for (int i=0; i< [arrData count]; i++){
NSLog(@"[%d]:%@",i,arrData[i]);
}
// 2.Fast iteration
for (id element in arrData){
NSLog(@"%@",element);
}
// 3.Blocks
[arrData enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"[%lu]:%@",idx,obj);
// Set stop to YES in case you want to break the iteration
}];
测试结果和源代码如下(您可以在应用程序中设置迭代次数)。时间以毫秒为单位,每个条目都是运行测试5-10次的平均结果。我发现通常精确到2-3个有效数字,之后会随每次运行而变化。这给出了小于1%的误差范围。测试是在iPhone 3G上运行的,因为那是我感兴趣的目标平台。
numberOfItems NSArray (ms) C Array (ms) Ratio
100 0.39 0.0025 156
191 0.61 0.0028 218
3,256 12.5 0.026 481
4,789 16 0.037 432
6,794 21 0.050 420
10,919 36 0.081 444
19,731 64 0.15 427
22,030 75 0.162 463
32,758 109 0.24 454
77,969 258 0.57 453
100,000 390 0.73 534
Cocoa提供的处理数据集的类(NSDictionary、NSArray、NSSet等)为管理信息提供了非常好的接口,而无需担心内存管理、重新分配等繁琐的操作。当然这也是有代价的。我认为很明显,使用包含NSNumbers的NSArray要比使用C Float数组进行简单迭代慢,因此我决定进行一些测试,结果令人震惊!我没有预料到会这么糟糕。注意:这些测试是在iPhone 3G上进行的,因为这是我感兴趣的目标平台。
在这个测试中,我对比了使用C float*和NSArray of NSNumbers进行非常简单的随机访问性能。
我创建了一个简单的循环来计算每个数组的内容,并使用mach_absolute_time()来计时。NSMutableArray平均需要花费400倍的时间!!(不是400%,而是400倍!相当于增加了40,000%)。
头文件:
// Array_Speed_TestViewController.h
// Array Speed Test
// Created by Mehmet Akten on 05/02/2009.
// Copyright MSA Visuals Ltd. 2009. All rights reserved.
#import <UIKit/UIKit.h>
@interface Array_Speed_TestViewController : UIViewController {
int numberOfItems; // number of items in array
float *cArray; // normal c array
NSMutableArray *nsArray; // ns array
double machTimerMillisMult; // multiplier to convert mach_absolute_time() to milliseconds
IBOutlet UISlider *sliderCount;
IBOutlet UILabel *labelCount;
IBOutlet UILabel *labelResults;
}
-(IBAction) doNSArray:(id)sender;
-(IBAction) doCArray:(id)sender;
-(IBAction) sliderChanged:(id)sender;
@end
实现:
// Array_Speed_TestViewController.m
// 数组速度测试
// 作者:Mehmet Akten,创建于2009年05月02日。
// 版权 MSA Visuals Ltd. 2009,保留所有权利。
#import "Array_Speed_TestViewController.h"
#include <mach/mach.h>
#include <mach/mach_time.h>
@implementation Array_Speed_TestViewController
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
NSLog(@"viewDidLoad");
[super viewDidLoad];
cArray = NULL;
nsArray = NULL;
// read initial slider value setup accordingly
[self sliderChanged:sliderCount];
// get mach timer unit size and calculater millisecond factor
mach_timebase_info_data_t info;
mach_timebase_info(&info);
machTimerMillisMult = (double)info.numer / ((double)info.denom * 1000000.0);
NSLog(@"machTimerMillisMult = %f", machTimerMillisMult);
}
// pass in results of mach_absolute_time()
// this converts to milliseconds and outputs to the label
-(void)displayResult:(uint64_t)duration {
double millis = duration * machTimerMillisMult;
NSLog(@"displayResult: %f milliseconds", millis);
NSString *str = [[NSString alloc] initWithFormat:@"%f milliseconds", millis];
[labelResults setText:str];
[str release];
}
// process using NSArray
-(IBAction) doNSArray:(id)sender {
NSLog(@"doNSArray: %@", sender);
uint64_t startTime = mach_absolute_time();
float total = 0;
for(int i=0; i<numberOfItems; i++) {
total += [[nsArray objectAtIndex:i] floatValue];
}
[self displayResult:mach_absolute_time() - startTime];
}
// process using C Array
-(IBAction) doCArray:(id)sender {
NSLog(@"doCArray: %@", sender);
uint64_t start = mach_absolute_time();
float total = 0;
for(int i=0; i<numberOfItems; i++) {
total += cArray[i];
}
[self displayResult:mach_absolute_time() - start];
}
// allocate NSArray and C Array
-(void) allocateArrays {
NSLog(@"allocateArrays");
// allocate c array
if(cArray) delete cArray;
cArray = new float[numberOfItems];
// allocate NSArray
[nsArray release];
nsArray = [[NSMutableArray alloc] initWithCapacity:numberOfItems];
// fill with random values
for(int i=0; i<numberOfItems; i++) {
// add number to c array
cArray[i] = random() * 1.0f/(RAND_MAX+1);
// add number to NSArray
NSNumber *number = [[NSNumber alloc] initWithFloat:cArray[i]];
[nsArray addObject:number];
[number release];
}
}
// callback for when slider is changed
-(IBAction) sliderChanged:(id)sender {
numberOfItems = sliderCount.value;
NSLog(@"sliderChanged: %@, %i", sender, numberOfItems);
NSString *str = [[NSString alloc] initWithFormat:@"%i items", numberOfItems];
[labelCount setText:str];
[str release];
[self allocateArrays];
}
//cleanup
- (void)dealloc {
[nsArray release];
if(cArray) delete cArray;
[super dealloc];
}
@end
来自:memo.tv
////////////////////
自从引入块以来,这允许用块迭代数组。它的语法不像快速枚举那样优美,但有一个非常有趣的特性:并发枚举。如果枚举顺序不重要,并且任务可以在没有锁定的情况下并行进行,那么在多核系统上,这可以提供相当大的加速。关于此,请参阅并发枚举部分。
[myArray enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {
[self doSomethingWith:object];
}];
[myArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[self doSomethingWith:object];
}];
/////////// NSFastEnumerator
快速枚举的思想是利用快速C数组访问来优化迭代。它不仅比传统的NSEnumerator更快,而且Objective-C 2.0还提供了非常简洁的语法。
id object;
for (object in myArray) {
[self doSomethingWith:object];
}
/////////////////
NSEnumerator是一种外部迭代的形式:[myArray objectEnumerator]返回一个对象。该对象有一个nextObject方法,我们可以在循环中调用它,直到它返回nil。
NSEnumerator *enumerator = [myArray objectEnumerator];
id object;
while (object = [enumerator nextObject]) {
[self doSomethingWith:object];
}
/////////////////
使用for循环递增整数并使用[myArray objectAtIndex:index]查询对象是最基本的枚举方式。
/////////////////
注:枚举是指按照一定顺序,逐个访问集合中的每个元素的过程。
NSUInteger count = [myArray count];
for (NSUInteger index = 0; index < count ; index++) {
[self doSomethingWith:[myArray objectAtIndex:index]];
}
////////////// 来源:darkdust.net
NSArray *langs = @[@"es", @"en", @"pt", @"it", @"fr"];
for (int i = 0; i < [langs count]; i++) {
NSString *lang = (NSString*) [langs objectAtIndex:i];
NSLog(@"%@, ",lang);
}
NSArray分类
中添加each
方法,因为您将需要它很多次。- (void)each:(void (^)(id object))block {
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
block(obj);
}];
}
请执行以下操作:
for (id object in array)
{
// statement
}
对于Swift
let arrayNumbers = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
// 1
for (index, value) in arrayNumbers.enumerated() {
print(index, value)
//... do somthing with array value and index
}
//2
for value in arrayNumbers {
print(value)
//... do somthing with array value
}
for
循环:for(;;) { id object = [ e nextObject ] ; if ( !e ) { break ; } ... 你的循环操作 ... }
- nielsbot