一、循环引用
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;
}
- 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
四、启动时间
- 启动分为2种: 冷启动和热启动
- 启动的时间分为两部分:main函数执行之前、main函数⾄应用启动完成
启动优化建议
main函数之前
减少动态库、合并一些动态库
减少Objc类、分类的数量、减少Selector数量
main函数⾄应用启动完成
耗时操作,不要放在finishLaunching方法中动态库对启动时间的影响测试
iOS Dynamic Framework 对App启动时间影响实测
五、应用瘦身
LinkMap查看文件大小
LSUnusedResources 查看未使用的文件
六、渲染
YYFpsLabel检查渲染
异步渲染
七、网络层
防止多次重复请求
网友评论