在程序开发中最常用的应该就是for循环对对象的遍历如NSArray, NSSet 或者NSDictionary。看似容易被忽视的点其实很影响app的性能开发。今天就对这个就自己的理解发表下自己的看法。
一.for循环的几种方法
1.1 最常用的循环方式
NSArray *testArray = @[@1,@2,@3,@4];
for(int a = 0; a < testArray.count; a++){
NSLog(@"%@",testArray[a]);
}
这段代码最大的问题就是循环每进行一次我们都会调用数组的计数方法. 数组的总数是不会改变的,因此每次都去调用一下这种做法是多余的。常用的优化如下:
NSArray *testArray = @[@1,@2,@3,@4];
NSUInteger count = testArray.count;
for(int a = 0; a < count; a++){
NSLog(@"%@",testArray[a]);
}
1.2 快速枚举
快速枚举是在 Objective-C 2.0 中作为传统的NSEnumerator的更便利的替代方法而引入的,新的方法顺便带来了一种新的循环语法, for…in 循环。
NSArray *testArray = @[@1,@2,@3,@4];
for(id num in testArray){
NSLog(@"%@",num);
}
要注意的是使用for in快速枚举NSMutableArray这类可变对象时要注意不能对容器进行修改,否则会导致遍历器抛出异常导致程序崩溃。
二.性能测试
我们这里用命令行运行这段代码以排除任何干扰最终结果的隐藏在幕后的保留或者排除处理。
clang -framework Foundation main.m -o main
static const NSUInteger arrayItems = 10000000;
NSMutableArray *array = [NSMutableArray arrayWithCapacity:arrayItems];
for (int i = 0; i < arrayItems; i++) [array addObject:@(i)];
array = [array copy];
CFTimeInterval start = CFAbsoluteTimeGetCurrent();
// 常用的for循环
for (NSUInteger i = 0; i < [array count]; i++){
id object = array[i];
}
CFTimeInterval forLoop = CFAbsoluteTimeGetCurrent();
NSLog(@"For loop: %g", forLoop - start);
//优化过的常用for循环
NSUInteger count = [array count];
for (NSUInteger i = 0; i < count; i++){
id object = array[i];
}
CFTimeInterval forLoopWithCountVar = CFAbsoluteTimeGetCurrent();
NSLog(@"Optimized for loop: %g", forLoopWithCountVar - forLoop);
CFTimeInterval enumeratorLoop = CFAbsoluteTimeGetCurrent();
// 快速枚举
for (id object in array){
}
CFTimeInterval forInLoop = CFAbsoluteTimeGetCurrent();
NSLog(@"For…in loop: %g", forInLoop - enumeratorLoop);
}
运行结果如下:
3DAE86E9-C7EC-4B4F-8C98-57BB9FE4B871.png
由此可以看出for in的性能最高,优化了的普通循环也要比正常的快很多。基于我们所见,如果所有其它的因素都一样的话,在循环遍历数组时你应该尝试去使用for...in循环。至于 NSSet 和 NSDictionary,也可以测试一下,结果是一样的。