ZJ_iOS面试

iOS 性能优化

2017-03-15  本文已影响135人  iOS104

列举在项目开发中可能遇到的优化点

- (BOOL)willDealloc {
    __weak id weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [weakSelf assertNotDealloc];
    });
    return YES;
}
- (void)assertNotDealloc {
     NSAssert(NO, @“”);
}
    _link = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayAction)];
    [_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
    
    - (void)displayAction {
    if (_lastTime == 0) {
        _lastTime = _link.timestamp;
        return;
    }
    
    _count++;
    NSTimeInterval delta = _link.timestamp - _lastTime;
    
    if (delta < 1) return;
    
    _lastTime = _link.timestamp;
    
    float fps = _count / delta;
    _count = 0;

    
    _fps = (int)round(fps);
    
    }

dispatch_queue_t formatterQueue = dispatch_queue_create("formatter queue", NULL);
NSDateFormatter *dateFormatter;
// ...
- (NSDate *)dateFromString:(NSString *)string
{
    __block NSDate *date = nil;
    dispatch_sync(formatterQueue, ^{
        date = [dateFormatter dateFromString:string];
    });
    return date;
}
static void runLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
    MyClass *object = (__bridge MyClass*)info;
    
    // 记录状态值
    object->activity = activity;
    
    // 发送信号
    dispatch_semaphore_t semaphore = moniotr->semaphore;
    dispatch_semaphore_signal(semaphore);
}
- (void)registerObserver
{
    CFRunLoopObserverContext context = {0,(__bridge void*)self,NULL,NULL};
    CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault,
                                                            kCFRunLoopAllActivities,
                                                            YES,
                                                            0,
                                                            &runLoopObserverCallBack,
                                                            &context);
    CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
    
    // 创建信号
    semaphore = dispatch_semaphore_create(0);
    
    // 在子线程监控时长
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        while (YES)
        {
            // 假定连续5次超时50ms认为卡顿(当然也包含了单次超时250ms)
            long st = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 50*NSEC_PER_MSEC));
            if (st != 0)
            {
                if (activity==kCFRunLoopBeforeSources || activity==kCFRunLoopAfterWaiting)
                {
                    if (++timeoutCount < 5)
                        continue;
                    
                    NSLog(@"好像有点儿卡哦");
                }
            }
            timeoutCount = 0;
        }
    });
}

/*
     第1个参数: 指定如何给observer分配存储空间
     第2个参数: 需要监听的状态类型/ kCFRunLoopAllActivities监听所有状态
     第3个参数: 是否每次都需要监听
     第4个参数: 优先级
     第5个参数: 监听到状态改变之后的回调
     */
    CFRunLoopObserverRef  observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        switch (activity) {
            case kCFRunLoopEntry:
                NSLog(@"即将进入runloop");
                break;
            case kCFRunLoopBeforeTimers:
                NSLog(@"即将处理timer");
                break;
            case kCFRunLoopBeforeSources:
                NSLog(@"即将处理source");
                break;
            case kCFRunLoopBeforeWaiting:
                NSLog(@"即将进入睡眠");
                break;
            case kCFRunLoopAfterWaiting:
                NSLog(@"刚从睡眠中唤醒");
                break;
            case kCFRunLoopExit:
                NSLog(@"即将退出");
                break;
            default:
                break;
        }
    });
    
    
    ```
- 5、使用Autorelease Pool
 - 在循环中,如果有很多autorelease对象,要放在循环内部。
- 6、UIImage缓存取舍
 - imagedNamed 默认加载图片成功后会内存中缓存图片,这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象.
 - tableView中或者反复使用的图片可以使用imageNamed
 - imageWithContentsOfFile 则仅只加载图片,不缓存。一次性大图片使用
- 7、加速启动时间
    - 程序启动时,除了界面上的操作,其他尽可能放在工作线程做。一些不重要的任务可以延后执行,例如判断版本升级提醒
- 8、UIKit 优化
    - 1、尽量使用不透明的View opaque为YES
    - 2、ImageView 使用合适大小的图片资源
    - 3、重用和延迟加载Views
    - 4、尽可能在TableViewCell时避免设置圆角,如果必须大量设置圆角,UIImageView 的圆角通过直接截取图片实现。其它视图的圆角可以通过 Core Graphics 画出圆角矩形实现。少量的话使用cornerRadius
    - 5、使用shadowPath来画阴影
    - 6、减少subviews的数量
    - 7、缓存行高
- 9、日志打点
    - 项目中有些业务异常需要在一定的环境才能重新,最好就好做好日志打点,预留埋点,在出现问题的时候方便排除问题
    - 出现问题的时候网速监控上报
- 10、合理的线程分配
    - 开的线程越来越多,线程的开销逐渐明显。
    - DB操作,日志操作,网络回调在各自固定的线程。不同业务,通过创建队列保持数据的一致性。
    - 主线程尽量少处理非UI的操作,同时控制整个APP子线程数量在一个合理的范围内。
- 11、建立合适的DB索引
- 12、cache
    - cache可能是所有性能优化中最常用的手段,但是cache建立的成本低,见效快,但是带来维护的成本却很高
    - 并发访问 cache 时,数据一致性问题
    - cache 线程安全问题
- 13、基本类的抽取
    - 基本类抽取可以提高开发效率
    - 工具类,比如View,Label,Button的快捷创建
- 14、Unit Tests 和 UI Testing 的使用
上一篇下一篇

猜你喜欢

热点阅读