美文网首页iOS 开发 Objective-C
iOS 底层 day29 循环引用 和 内存泄露

iOS 底层 day29 循环引用 和 内存泄露

作者: 望穿秋水小作坊 | 来源:发表于2020-10-14 14:29 被阅读0次

一、UIView 的 block 写动画

1. 请问下面代码有内存泄露吗?有循环引用吗?
// 情况一
@implementation UIViewAnimationsBlock
- (void)viewDidLoad {
    [super viewDidLoad];
    NSTimeInterval duration = 1000;
    [UIView animateWithDuration:duration animations:^{
        [self.view.superview layoutIfNeeded];
    }];
}
- (void)dealloc {
    NSLog(@"%s", __func__);
}
@end
  • 没有内存泄露,也没有循环引用
2. UIViewblock 写动画时不需要考虑循环引用的原因是?
  • block 会立即执行,所以并不会持有 block。其中 duration 延迟时间并不能决定 block 执行的时机,block 始终是瞬间执行的。
  • 这里涉及了 CoreAnimation (核心动画)相关的知识:UIView 层Layer 层data 数据层
  • UIView 层block 仅仅是提供了类似快照 data 的变化。
  • 当真正执行 Animation 动画时才会将 "原有状态""执行完 block 的状态" 做一个差值,来去做动画。

二、NSNotificationCenter 的 block 使用

1. 请问下面代码有内存泄露吗?有循环引用吗?
// 情况二
@implementation NSNotificationCenterBlock
- (void)viewDidLoad {
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserverForName:@"someNotification"
                           object:nil
                           queue:[NSOperationQueue mainQueue]
                       usingBlock:^(NSNotification * notification) {
        NSLog(@"%@", self);
    }];
}
- (void)remove {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)dealloc {
    [self remove];
    NSLog(@"%s", __func__);
}
@end
  • 内存泄露,没有循环引用
2. 情况二解析
  • [NSNotificationCenter defaultCenter] 是一个单例,它需要在接到通知时候调用 block,所以[NSNotificationCenter defaultCenter] 需要持有 block,会对 block 调用 -copy 方法。
  • [NSNotificationCenter defaultCenter] 持有 blockblock 持有 self[NSNotificationCenter defaultCenter] 不会释放,因此 self 也不会得到释放,也不会调用 -dealloc 方法。
  • 所以不存在循环引用,但是存在内存泄露
3. 请问下面代码有内存泄露吗?有循环引用吗?
// 情况三
@interface NSNotificationCenterIVARBlock ()
@property (nonatomic, strong) id observer;
@end
@implementation NSNotificationCenterIVARBlock
- (void)viewDidLoad {
    [super viewDidLoad];
    self.observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
                                                                         object:nil
                                                                          queue:nil
                                                                     usingBlock:^(NSNotification *note) {
                                                                         NSLog(@"%@", self);
    }];
}
- (void)remove {
    [[NSNotificationCenter defaultCenter] removeObserver:self.observer];
}
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self remove];
}
- (void)dealloc {
    NSLog(@"%s", __func__);
}
@end
  • 存在循环引用,也存在内存泄露
4. 情况三解析
  • self 持有 observerobserver 持有 blockblock 指持有 self;这就造成了循环引用。
  • 虽然 -remove方法调用observer[NSNotificationCenter defaultCenter] 移除,但是不能改变已经形成的循环引用。
5. 如何利用 Xcode 检查情况三存在的内存泄露和循环引用?
  • 方法一:可用 Xcode-instruments-Leak 工具查看
  • 打开方法 Product → profile → leaks
leaks 查看NSNotificationCenterIVARBlock 内存泄露图
  • 方法二:借助 Xcode 的 Debug Memory Graph 功能查看
    Xcode 的 `Debug Memory Graph`开启
循环引用结构

三、GCD 和 NSOperationQueue 的 block 使用

1. 请问下面代码有内存泄露吗?有循环引用吗?
// 情况四
@interface GCDBlock ()
@property(nonatomic, strong) dispatch_queue_t myQueue;
@end

@implementation GCDBlock
- (void)viewDidLoad {
    [super viewDidLoad];
    self.myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(self.myQueue, ^{
        [self doSomething];
    });
}
- (void)doSomething {
    NSLog(@"%s", __func__);
}
- (void)dealloc {
    NSLog(@"%s", __func__);
}
@end
  • 没有内存泄露,也没有循环引用
2. 请问下面代码有内存泄露吗?有循环引用吗?
// 情况五
@implementation NSOperationQueueBlock
- (void)viewDidLoad {
    [super viewDidLoad];
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{ NSLog(@"%@",self); }];
}
- (void)dealloc {
    NSLog(@"%s", __func__);
}
@end
  • 没有内存泄露,也没有循环引用
3. 情况四 情况五解析
  • 针对 GCDNSOperationQueue 的问题,我们只需记住,block 执行完毕之后,block 将会被释放掉。从而破除了循环引用和内存泄露

相关文章

  • iOS 底层 day29 循环引用 和 内存泄露

    一、UIView 的 block 写动画 1. 请问下面代码有内存泄露吗?有循环引用吗? 没有内存泄露,也没有循环...

  • iOS进阶教程:内存泄露的检测

    iOS内存这块,虽然系统会自动管理,但是自己代码不严谨,非常容易产生内存泄露、内存释放、循环引用这些类似问题。 介...

  • iOS循环引用

    什么是循环引用? 循环引用:是指多个对象相互引用,导致内存无法释放,从而导致内存泄露。 循环引用的四种情况? 父类...

  • Swift 循环引用实例解析

    iOS 使用引用计数来进行内存管理。在某些情况下,代码编写不慎会产生循环引用,进而导致内存泄露。根据我们目前项目中...

  • 在iOS上自动检测内存泄露

    2016-04-19 06:49编辑:cocopeng分类:iOS开发来源:付军的博客 12 内存泄露循环引用 招...

  • iOS 内存泄露监测

    iOS可能存在的内存泄露: block 循环引用。当一个对象有一个block属性,而block属性又引用这个对象本...

  • iOS 开发中常见的内存问题有哪些?

    原文:iOS面试题大全 内存问题主要包括两个部分,一个是iOS中常见循环引用导致的内存泄露 ,另外就是大量数据加载...

  • iOS 性能优化

    列举在项目开发中可能遇到的优化点 1、内存泄露检测可能出现内存泄露的地方:循环引用,block强引用,NSTime...

  • iOS 内存管理 部分二

    主要讲解CADisplayLink 和 NSTimer 的循环引用问题 iOS 内存管理 部分一iOS 内存管...

  • 内存泄露和循环引用问题

    内存泄露和循环引用问题 开发项目时你怎么检查内存泄漏 静态分析analyze instruments里有一个lea...

网友评论

    本文标题:iOS 底层 day29 循环引用 和 内存泄露

    本文链接:https://www.haomeiwen.com/subject/qmuipktx.html