iOS性能优化 — 四、内存泄露检测 - 图1

上篇文章为大家讲解了安装包瘦身,这篇文章继续为大家讲解下内存泄露检测。

  • 造成内存泄漏原因
  • 常见循环引用及解决方案
  • 怎么检测循环引用

造成内存泄漏原因

  • 在用C/C++时,创建对象后未销毁,比如调用malloc后不free、调用new后不delete;
  • 调用CoreFoundation里面的C方法后创建对对象后不释放。比如调用CGImageCreate不调用CGImageRelease;
  • 循环引用。当对象A和对象B互相持有的时候,就会产生循环引用。常见产生循环引用的场景有在VC的cellForRowAtIndexPath方法中cell block引用self。

常见循环引用及解决方案

1) 在VC的cellForRowAtIndexPath方法中cell的block直接引用self或者直接以_形式引用属性造成循环引用。

  1. cell.clickBlock = ^{
  2. self.name = @"akon";
  3. };
  4. cell.clickBlock = ^{
  5. _name = @"akon";
  6. };

解决方案:把self改成weakSelf;

  1. __weak typeof(self)weakSelf = self;
  2. cell.clickBlock = ^{
  3. weakSelf.name = @"akon";
  4. };

2)在cell的block中直接引用VC的成员变量造成循环引用。

  1. //假设 _age为VC的成员变量
  2. @interface TestVC(){
  3. int _age;
  4. }
  5. cell.clickBlock = ^{
  6. _age = 18;
  7. };

解决方案有两种:

  • 用weak-strong dance
  1. __weak typeof(self)weakSelf = self;
  2. cell.clickBlock = ^{
  3. __strong typeof(weakSelf) strongSelf = weakSelf;
  4. strongSelf->age = 18;
  5. };
  • 把成员变量改成属性
  1. //假设 _age为VC的成员变量
  2. @interface TestVC()
  3. @property(nonatomic, assign)int age;
  4. @end
  5. __weak typeof(self)weakSelf = self;
  6. cell.clickBlock = ^{
  7. weakSelf.age = 18;
  8. };

3)delegate属性声明为strong,造成循环引用。

  1. @interface TestView : UIView
  2. @property(nonatomic, strong)id<TestViewDelegate> delegate;
  3. @end
  4. @interface TestVC()<TestViewDelegate>
  5. @property (nonatomic, strong)TestView* testView;
  6. @end
  7. testView.delegate = self; //造成循环引用

解决方案:delegate声明为weak

  1. @interface TestView : UIView
  2. @property(nonatomic, weak)id<TestViewDelegate> delegate;
  3. @end

4)在block里面调用super,造成循环引用。

  1. cell.clickBlock = ^{
  2. [super goback]; //造成循环应用
  3. };

解决方案,封装goback调用

  1. __weak typeof(self)weakSelf = self;
  2. cell.clickBlock = ^{
  3. [weakSelf _callSuperBack];
  4. };
  5. - (void) _callSuperBack{
  6. [self goback];
  7. }

5)block声明为strong
解决方案:声明为copy
6)NSTimer使用后不invalidate造成循环引用。
解决方案:

  • NSTimer用完后invalidate;
  • NSTimer分类封装
  1. * (NSTimer *)ak_scheduledTimerWithTimeInterval:(NSTimeInterval)interval
  2. block:(void(^)(void))block
  3. repeats:(BOOL)repeats{
  4. return [self scheduledTimerWithTimeInterval:interval
  5. target:self
  6. selector:@selector(ak_blockInvoke:)
  7. userInfo:[block copy]
  8. repeats:repeats];
  9. }
  10. * (void)ak_blockInvoke:(NSTimer*)timer{
  11. void (^block)(void) = timer.userInfo;
  12. if (block) {
  13. block();
  14. }
  15. }

怎么检测循环引用

  • 静态代码分析。 通过Xcode->Product->Anaylze分析结果来处理;
  • 动态分析。用MLeaksFinder或者Instrument进行检测。

资料推荐

如果你正在跳槽或者正准备跳槽不妨动动小手,添加一下咱们的交流群1012951431来获取一份详细的大厂面试资料为你的跳槽多添一份保障。

iOS性能优化 — 四、内存泄露检测 - 图2