iOS 对象的 setter 方法性能测试

最近在挑选 JSON 和 Object 之间相互转换的工具,对比了下老牌的 Mantle 和新秀 YYModel。
从 YYModel 的自己的测试结果来看,在复杂转换下有 4 倍左右的速度差异。简单的 model 转化更是有约 30倍 的速度差异。
测试结果可以在 YYModel 的主页上找到。

细读了下代码发现差异原因主要在赋值属性上。
Mandle 用了 KVC 的 setValue:forKey:, 而 YYModel 用了对象属性的 Setter 方法。 这也就是最直接的速度差异。

苹果关于 KVC 方法实现可以参看说明文档. 正是由于复杂的 key 查找方法才产生了如此大的速度差异。

写了个测试的 Demo 测试下不同的赋值方法和编译器优化级别的速度:

debug: [m setValue:@"hello" forKey:@"_stringValue"]: 0.000504
-Os:   [m setValue:@"hello" forKey:@"_stringValue"]: 0.000395
-O3:   [m setValue:@"hello" forKey:@"_stringValue"]: 0.000374
----------------------------------------------------------------
debug: [m setValue:@"hello" forKey:@"stringValue"]:  0.000188
-Os:   [m setValue:@"hello" forKey:@"stringValue"]:  0.000174
-O3:   [m setValue:@"hello" forKey:@"stringValue"]:  0.000134
----------------------------------------------------------------
debug: [m setStringValue:@"hello"]:                  0.000014
-Os:   [m setStringValue:@"hello"]:                  0.000032
-O3:   [m setStringValue:@"hello"]:                  0.000024
----------------------------------------------------------------
debug: m->_stringValue = @"hello":                   0.000017
-Os:   m->_stringValue = @"hello":                   0.000023
-O3:   m->_stringValue = @"hello":                   0.000014
----------------------------------------------------------------
debug: m.stringValue = @"hello":                     0.000014
-Os:   m.stringValue = @"hello":                     0.000031
-O3:   m.stringValue = @"hello":                     0.000023
----------------------------------------------------------------
debug: [m setValue:n forKey:@"_integerValue"]:       0.000393
-Os:   [m setValue:n forKey:@"_integerValue"]:       0.000270
-O3:   [m setValue:n forKey:@"_integerValue"]:       0.000239
----------------------------------------------------------------
debug: [m setValue:n forKey:@"integerValue"]:        0.000314
-Os:   [m setValue:n forKey:@"integerValue"]:        0.000284
-O3:   [m setValue:n forKey:@"integerValue"]:        0.000306
----------------------------------------------------------------
debug: [m setIntegerValue:123]:                      0.000008
-Os:   [m setIntegerValue:123]:                      0.000005
-O3:   [m setIntegerValue:123]:                      0.000005
----------------------------------------------------------------
debug: m->_integerValue = 123:                       0.000006
-Os:   m->_integerValue = 123:                       0.000002
-O3:   m->_integerValue = 123:                       0.000002
----------------------------------------------------------------
debug: m.integerValue = 123:                         0.000053
-Os:   m.integerValue = 123:                         0.000012
-O3:   m.integerValue = 123:                         0.000005
----------------------------------------------------------------

以上测试为运行 10000 次的结果。从测试结果来看如果 key 为 Ivar 的名字,那么最大差距约为 36 倍! 即使是使用属性名为 key 也有 13倍 左右的速度差异。

开启了不同的编译器优化级别,-O3 和 -Os 的部分测试速度反而要比 debug 版慢了,目前还不清楚速度下降的原因。

测试设备为 iPhone 6, iOS 9.3.1。 测试用例参看:
https://github.com/6david9/SetterBenchmark/blob/master/Benchmark/Benchmark/ViewController.m

Written on 2016-04-19