iOS之道

性能优化

2020-01-10  本文已影响0人  没戏还在演戏

一、循环引用

1.第一种方式 weak+strong(最常用)

- (void)one{
    __weak typeof(self) weakSelf = self;
    self.block = ^{
        __strong typeof(self) strongSelf = weakSelf;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@",strongSelf.name); // self - nil name - nil
        });
    };
    
    self.block();
}

2.第二种方式__block

- (void)two{
    __block ViewController *vc = self; // vc 结构体
    self.block = ^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@",vc.name); // self - nil name - nil
            vc = nil;
        });
    };
    self.block();
}

3.第三种方式 传参(效率最高)

self.blockVc = ^(ViewController *vc){
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@",vc.name); // self - nil name - nil
        });
    };
    self.blockVc(self);

二、强引用

- (void)initTimer {
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self.target selector:@selector(timerSel) userInfo:nil repeats:YES];
}
- (void)timerSel{
    num++;
    NSLog(@"num----> %d",num);
}

因为runloop -> timer -> target -> self 造成了强引用
1.简陋的解决

-(void)viewWillDisappear:(BOOL)animated {
    [self.timer invalidate];
    self.timer = nil;
}

2.好一点的方式,但是不够灵活

-(void)didMoveToParentViewController:(UIViewController *)parent{
    if (parent == nil) {
        [self.timer invalidate];
        self.timer = nil;
    }
    NSLog(@"结束");
}

3.中间层
定义一个中间层

@interface YHTimerWapper : NSObject
- (instancetype)yh_initWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
- (void)yh_invalidate;
@end
@interface YHTimerWapper()
@property (nonatomic, weak) id target;
@property (nonatomic, assign) SEL aSelector;
@property (nonatomic, strong) NSTimer *timer;
@end
@implementation YHTimerWapper
- (instancetype)yh_initWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo{
    if (self == [super init]) {
        self.target     = aTarget;
        self.aSelector  = aSelector;
        self.timer      = [NSTimer scheduledTimerWithTimeInterval:ti target:self selector:@selector(timerSel) userInfo:userInfo repeats:yesOrNo];
    }
    return self;
}
- (void)timerSel{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    // 让编译器出栈,恢复状态,继续编译后续的代码!
    if ([self.target respondsToSelector:self.aSelector]) {
        [self.target performSelector:self.aSelector];
    }
#pragma clang diagnostic pop
}
- (void)yh_invalidate{
    [self.timer invalidate];
    self.timer = nil;
}

使用

- (void)viewDidLoad {
    [super viewDidLoad];
    //中间层(RACKVOWapper)
    // self -> timerWapper(在self的dealloc方法断开) <-> timer <- runloop
    self.timerWapper = [[YHTimerWapper alloc] yh_initWithTimeInterval:1 target:self selector:@selector(timerSel) userInfo:nil repeats:YES];
}
- (void)dealloc{
    [self.timerWapper lg_invalidate];
}

4.使用block

self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
        NSLog(@"num ");
}];
- (void)dealloc{
    [self.timer invalidate];
    self.timer = nil;
}
  1. NSProxy
    是跟NSObject同级的类,加载迅速,消息转发形式更加清晰
@interface YHProxy : NSProxy
+ (instancetype)proxyWithTransformObject:(id)object;
@end
@interface YHProxy()
@property (nonatomic, weak) id object;
@end
@implementation YHProxy
+ (instancetype)proxyWithTransformObject:(id)object{
    YHProxy *proxy = [YHProxy alloc];
    proxy.object = object;
    return proxy;
}
// sel - imp -
// 消息转发 self.object
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
    return [self.object methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation{
    if (self.object) {
        [invocation invokeWithTarget:self.object];
    }
}
@end

使用

self.proxy = [YHProxy proxyWithTransformObject:self];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self.proxy selector:@selector(timerSel) userInfo:nil repeats:YES];

三、内存泄漏检查方式

1、静态分析Analyze
2、instrument
3、MLeaksFinder(更方便)
4、dealloc

四、启动时间

  1. 启动分为2种: 冷启动和热启动
  2. 启动的时间分为两部分:main函数执行之前、main函数⾄应用启动完成
    启动优化建议
    main函数之前
    减少动态库、合并一些动态库
    减少Objc类、分类的数量、减少Selector数量
    main函数⾄应用启动完成
    耗时操作,不要放在finishLaunching方法中

动态库对启动时间的影响测试
iOS Dynamic Framework 对App启动时间影响实测

五、应用瘦身

LinkMap查看文件大小
LSUnusedResources 查看未使用的文件

六、渲染

YYFpsLabel检查渲染
异步渲染

七、网络层

防止多次重复请求

上一篇下一篇

猜你喜欢

热点阅读