我正在寻找在NSArray上迭代的标准习语。我的代码需要适合OS X 10.4+。
当前回答
测试结果和源代码如下(您可以在应用程序中设置迭代次数)。时间以毫秒为单位,每个条目是运行测试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
The classes provided by Cocoa for handling data sets (NSDictionary, NSArray, NSSet etc.) provide a very nice interface for managing information, without having to worry about the bureaucracy of memory management, reallocation etc. Of course this does come at a cost though. I think it's pretty obvious that say using an NSArray of NSNumbers is going to be slower than a C Array of floats for simple iterations, so I decided to do some tests, and the results were pretty shocking! I wasn't expecting it to be this bad. Note: these tests are conducted on an iPhone 3G as that's the target platform I was interested in.
在这个测试中,我做了一个非常简单的随机访问性能比较C float*和NSNumbers的NSArray
我创建了一个简单的循环来总结每个数组的内容,并使用mach_absolute_time()计时。NSMutableArray平均需要400倍的时间!!(不是400%,只是400倍!长了40000% !)
标题:
/ / Array_Speed_TestViewController.h
//阵列速度测试
//由Mehmet Akten于05/02/2009创作。
//版权所有MSA视觉有限公司2009。版权所有。
#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于05/02/2009创作。
//版权所有MSA视觉有限公司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];
}
/////////////////
, objectAtIndex:枚举
使用一个递增整数的for循环并使用[myArray objectAtIndex:index]查询对象是最基本的枚举形式。
NSUInteger count = [myArray count];
for (NSUInteger index = 0; index < count ; index++) {
[self doSomethingWith:[myArray objectAtIndex:index]];
}
////////////// 来自:darkdust.net
其他回答
为迅速
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
}
将每个方法添加到NSArray类别中,你会非常需要它
来自ObjectiveSugar的代码
- (void)each:(void (^)(id object))block {
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
block(obj);
}];
}
适用于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
}
下面是如何声明一个字符串数组并遍历它们:
NSArray *langs = @[@"es", @"en", @"pt", @"it", @"fr"];
for (int i = 0; i < [langs count]; i++) {
NSString *lang = (NSString*) [langs objectAtIndex:i];
NSLog(@"%@, ",lang);
}
这样做:
for (id object in array)
{
// statement
}
推荐文章
- 理解设置
- 架构i386的未定义符号:_OBJC_CLASS_$_SKPSMTPMessage",引用自:错误
- Objective-C中方法混合的危险是什么?
- 如何使用接口生成器创建的nib文件加载UIView
- 如何设置回退按钮文本在Swift
- 如何比较两个nsdate:哪个是最近的?
- 使UINavigationBar透明
- Scala中的Case对象与枚举
- 删除/重置核心数据中的所有条目?
- Swift to Objective-C头未在Xcode 6中创建
- setNeedsLayout vs. setNeedsUpdateConstraints和layoutIfNeeded vs. updateConstraintsIfNeeded
- 不区分大小写的比较
- 编译警告:对于架构i386,没有处理文件的规则
- 从ViewController调用App Delegate方法
- 解释iOS7中automyadjustsscrollviewinsets, extendedlayoutinclesopaquebars, edgesForExtendedLayout之间的区别