当实习生的时候才第一次考虑内存泄漏的问题,当时做的也很简单,无非就是几个步骤:
1.注意对self等的弱化指针的声明方法,代理使用weak,而block使用copy。 2.释放该类中的NSNotification(通知)、NSTimer(定时器)等 3.在该类的dealloc中打印,通过哪些类没有打印结果查看是出问题的类。
最近又对内存泄露有了一些新的了解,关于以上的几点有一些更好的做法:
1.self指针的弱化
关于self的弱化方式有好几种方式:
__weak __typeof(self) weakSelf = self;
__weak __typeof(&*self) weakSelf = self;
__weak UIViewController *weakSelf =self;
复制代码
很简单,一般会直接放在一个全局的文件中公用:
#define WS(ws) __weak __typeof(&*self)ws = self;
复制代码
在block中使用实例变量时,也会引起内存泄露的警告,所以最好将要在block中使用的对象声明为属性。 如:使用下方的方法声明的bottomDetailCollectionView是一个强指针,如果在block中使用的话,会导致循环。
lZBottomDetailCollectionView *bottomDetailCollectionView = [[lZBottomDetailCollectionView alloc] init];
self.bottomDetailCollectionView = bottomDetailCollectionView;
[self.view addSubview:bottomDetailCollectionView];
WS(ws)
topTitleCollectionView.topTitleSelected = ^(NSInteger tag) {
[ws addTopTitleUMengEvent:tag];
NSIndexPath *indexpath = [NSIndexPath indexPathForItem:tag inSection:0];
[bottomDetailCollectionView scrollToItemAtIndexPath:indexpath atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
};
复制代码
应该将block中的bottomDetailCollectionView改为弱引用的ws.bottomDetailCollectionView。
2.NSTimer等的释放
刚开始学的时候,只知道NSTimer在调用方法:
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(doSomething) userInfo:nil repeats:YES];
复制代码
会对self直接retain,导致循环调用,所以在实现NSTimer的地方必须手动加上系统相关的释放方法:
[self.timer invalidate];
self.timer = nil;
复制代码
但是很容易忘记写这些方法,所以参考YYImage中的方法进行修改:
① 创建一个继承与NSProxy的子类
@interface lZWeekProxy : NSProxy
@property (nonatomic, weak, readonly) id target;
-(instancetype)initWithTarget:(id)target;
+(instancetype)proxyWithTarget:(id)target;
@end
@implementation lZWeekProxy
-(instancetype)initWithTarget:(id)target
{
_target = target;
return self;
}
+(instancetype)proxyWithTarget:(id)target
{
return [[lZWeekProxy alloc] initWithTarget:target];
}
- (id)forwardingTargetForSelector:(SEL)selector {
return _target;
}
@end
复制代码
对于为什么要继承于NSProxy,我的理解是: NSProxy类似于NSObject,是一个基类。其次NSProxy是一个虚类,基本上只是关于消息转发的方法,而需要的类其中一个目的就是将消息转发回target目标对象中的方法实现。
① 创建NSTimer
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:[lZWeekProxy proxyWithTarget:self] selector:@selector(doSomething) userInfo:nil repeats:YES];
复制代码
在创建NSTimer时,不再对self强引用。即便没有调用系统的方法,也不会引起内存泄露的情况。
3.判断类是否出现内存泄露
一开始的时候确实傻乎乎的通过dealloc方法是否打印的方式判断,网络上确实有一些已经很使用的工具,通过追踪该对象的引用计数方式进行判断。当然任何工具都会有一定的偏差,在实际的开发中还是需要一定的判断力:
在开发中难免会出现内存泄露的情况,所以一定要多加注意