iOS 性能小点

  这篇文章只是对一些测试结果进行展现,但可以根据这些点,开发的时候尽量避免不必要的性能问题。


 

  本文中主要做了两项测试,对成员变量的设置及拼接字用不同方式下的耗时。虽然测试代码很简单,但还是贴一下

//
//  XMCPerformanceDemoTests.m
//  XMCPerformanceDemoTests
//
//  Created by xianmingchen on 16/7/12.
//  Copyright © 2016年 xianmingchen. All rights reserved.
//

#import <XCTest/XCTest.h>
#import "XMCPerformanceUtil.h"
#import <objc/message.h>
#import <CoreFoundation/CoreFoundation.h>

@interface XMCPerformanceDemoTests : XCTestCase
@property (nonatomic, strong) NSString *name;
@end

@implementation XMCPerformanceDemoTests
@synthesize name = _name;
- (void)setUp {
    [super setUp];
    // Put setup code here. This method is called before the invocation of each test method in the class.
}

- (void)tearDown {
    // Put teardown code here. This method is called after the invocation of each test method in the class.
    [super tearDown];
}

- (void)testExample {
    // This is an example of a functional test case.
    // Use XCTAssert and related functions to verify your tests produce the correct results.
}

#pragma mark - testSetValue
#define kName @"name"
const NSUInteger kSetValueCount = 100000000;
- (void)testSetValueWithProperty
{
    // Put the code you want to measure the time of here.
    [XMCPerformanceUtil excuteWithCount:kSetValueCount tagName:__func__ block:^{
        self.name = nil;
        self.name = kName;
    }];
}

- (void)testSetValueWithIvar
{
    [XMCPerformanceUtil excuteWithCount:kSetValueCount tagName:__func__ block:^{
        _name = nil;
        _name = kName;
    }];
}

- (void)testSetValueWithKVC
{
    [XMCPerformanceUtil excuteWithCount:kSetValueCount tagName:__func__ block:^{
        [self setValue:nil forKey:kName];
        [self setValue:kName forKey:kName];
    }];
}

- (void)testSetValueWithMsgSend
{
    [XMCPerformanceUtil excuteWithCount:kSetValueCount tagName:__func__ block:^{
        ((void (*) (id, SEL, id))objc_msgSend)(self, @selector(setName:), nil);
        ((void (*) (id, SEL, id))objc_msgSend)(self, @selector(setName:), kName);
    }];
}


#pragma mark - testStringCombine
#define kCombineStringOne @"CombineStringOne"
#define kCombineStringTwo @"kCombineStringTwo"
#define kCombiedStringLeng [kCombineStringOne length] + [kCombineStringOne length]
const NSUInteger kStringCombineCount = 1000000;
- (void)testStringCombineWithFormat
{
    [XMCPerformanceUtil excuteWithCount:kStringCombineCount tagName:__func__ block:^{
        NSString *string = [NSString stringWithFormat:@"%@%@", kCombineStringOne, kCombineStringTwo];
    }];
}

- (void)testStringCombineWithAppend
{
    NSUInteger length = kCombiedStringLeng;
    [XMCPerformanceUtil excuteWithCount:kStringCombineCount tagName:__func__ block:^{
        NSMutableString *string = [NSMutableString stringWithCapacity:kCombiedStringLeng];
        [string appendString:kCombineStringOne];
        [string appendString:kCombineStringTwo];
    }];
}

- (void)testStringCombineWithCFMethod
{
    NSUInteger length = kCombiedStringLeng;
    [XMCPerformanceUtil excuteWithCount:kStringCombineCount tagName:__func__ block:^{
        CFMutableStringRef cfString = CFStringCreateMutable(NULL, length);
        CFStringAppend(cfString, (__bridge CFStringRef)kCombineStringOne);
        CFStringAppend(cfString, (__bridge CFStringRef)kCombineStringTwo);
    }];
}

- (void)testStringCombineWithSprintf
{
    NSUInteger length = kCombiedStringLeng;
    [XMCPerformanceUtil excuteWithCount:kStringCombineCount tagName:__func__ block:^{
        char *buf = new char[length + 1];
        sprintf(buf, "%s%s", kCombineStringOne.UTF8String, kCombineStringTwo.UTF8String);
    }];

}
@end
//
//  XMCPerformanceUtil.m
//  XMCPerformanceDemo
//
//  Created by xianmingchen on 16/7/12.
//  Copyright © 2016年 xianmingchen. All rights reserved.
//

#import "XMCPerformanceUtil.h"

@implementation XMCPerformanceUtil
+ (void)excuteWithCount:(NSUInteger)count tagName:(const char *)tagName block:(void(^)())excuteBlock
{
    if (!excuteBlock || tagName == NULL)
    {
        return;
    }
    
    NSLog(@"%s beginTest", tagName);
    NSDate *beginDate = [NSDate date];
    for (NSInteger i = 0; i < count; i++)
    {
        excuteBlock();
    }
    
    NSDate *endDate = [NSDate date];
    NSTimeInterval timeInterval = [endDate timeIntervalSinceDate:beginDate];
    NSLog(@"%s endTest", tagName);
    NSLog(@"%s take %f seconds", tagName, timeInterval);
}
@end

对于成员变量的设置进行了一亿次,结果如下:

2016-07-14 15:11:45.287 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testSetValueWithIvar] beginTest
2016-07-14 15:11:46.996 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testSetValueWithIvar] endTest
2016-07-14 15:11:46.996 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testSetValueWithIvar] take 1.708654 seconds
Test Case '-[XMCPerformanceDemoTests testSetValueWithIvar]' passed (1.710 seconds).
Test Case '-[XMCPerformanceDemoTests testSetValueWithKVC]' started.
2016-07-14 15:11:46.997 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testSetValueWithKVC] beginTest
2016-07-14 15:12:00.976 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testSetValueWithKVC] endTest
2016-07-14 15:12:00.976 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testSetValueWithKVC] take 13.978292 seconds
Test Case '-[XMCPerformanceDemoTests testSetValueWithKVC]' passed (13.979 seconds).
Test Case '-[XMCPerformanceDemoTests testSetValueWithMsgSend]' started.
2016-07-14 15:12:00.977 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testSetValueWithMsgSend] beginTest
2016-07-14 15:12:03.537 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testSetValueWithMsgSend] endTest
2016-07-14 15:12:03.537 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testSetValueWithMsgSend] take 2.559113 seconds
Test Case '-[XMCPerformanceDemoTests testSetValueWithMsgSend]' passed (2.560 seconds).
Test Case '-[XMCPerformanceDemoTests testSetValueWithProperty]' started.
2016-07-14 15:12:03.538 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testSetValueWithProperty] beginTest
2016-07-14 15:12:06.131 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testSetValueWithProperty] endTest
2016-07-14 15:12:06.132 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testSetValueWithProperty] take 2.593149 seconds
Test Case '-[XMCPerformanceDemoTests testSetValueWithProperty]' passed (2.594 seconds).

可以看到按大小排列 KVC(testSetValueWithKVC) > 使用.方法调用(testSetValueWithProperty)>使用objc_msgSend(testSetValueWithMsgSend)> 直接用成员变量(testSetValueWithIvar)。具体原理可自行了解,也不难。看回结果,比较值得关注的是通过KVC的性能实现是太低了,非必要不建议使用,面使用成员变量比使用.方法还是高一点点,推荐。

 

对于字符串的拼接是不同方式进行了一百万次操作,结果如下:

2016-07-14 15:12:06.133 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testStringCombineWithAppend] beginTest
2016-07-14 15:12:06.798 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testStringCombineWithAppend] endTest
2016-07-14 15:12:06.798 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testStringCombineWithAppend] take 0.664613 seconds
Test Case '-[XMCPerformanceDemoTests testStringCombineWithAppend]' passed (0.666 seconds).
Test Case '-[XMCPerformanceDemoTests testStringCombineWithCFMethod]' started.
2016-07-14 15:12:06.799 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testStringCombineWithCFMethod] beginTest
2016-07-14 15:12:07.271 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testStringCombineWithCFMethod] endTest
2016-07-14 15:12:07.272 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testStringCombineWithCFMethod] take 0.472003 seconds
Test Case '-[XMCPerformanceDemoTests testStringCombineWithCFMethod]' passed (0.473 seconds).
Test Case '-[XMCPerformanceDemoTests testStringCombineWithFormat]' started.
2016-07-14 15:12:07.273 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testStringCombineWithFormat] beginTest
2016-07-14 15:12:08.499 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testStringCombineWithFormat] endTest
2016-07-14 15:12:08.499 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testStringCombineWithFormat] take 1.225532 seconds
Test Case '-[XMCPerformanceDemoTests testStringCombineWithFormat]' passed (1.416 seconds).
Test Case '-[XMCPerformanceDemoTests testStringCombineWithSprintf]' started.
2016-07-14 15:12:08.689 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testStringCombineWithSprintf] beginTest
2016-07-14 15:12:09.012 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testStringCombineWithSprintf] endTest
2016-07-14 15:12:09.012 XMCPerformanceDemo[31074:2951062] -[XMCPerformanceDemoTests testStringCombineWithSprintf] take 0.322741 seconds

可以看到 stringWithFormat > Append > CFAppend > Sprinf。系统的stringWithFormat其实效率其实是很低的。做这个测试原由是我们发现写日志代码中stringWithFormat耗时很大,后面改成了Sprinf拼接,性能提升一半以上。并不是说这样我们就不用stringWithFormat。但有些情况最好不用,如:调用次数好多的地方(如日志),性能要求高(tableViewCellForRow中)等。测试代码Demo传送门

(未完待续,还没其它点子,欢迎补充...)

posted on 2016-07-14 15:40  chenxianming  阅读(493)  评论(0编辑  收藏  举报

导航