美文网首页iOS Developer
【Tips】 拒绝循环引用

【Tips】 拒绝循环引用

作者: longjianjiang | 来源:发表于2017-03-01 21:31 被阅读65次

前言

最近项目中检查是否有内存泄露,发现大部分的情况都是由于block的循环引用而导致的内存泄露,所以借此机会来记录下常见的循环引用的例子,如果不全,还请各位在评论区多多补充。(哈哈,抛砖引玉😄)

1)
@interface LJTestViewController ()

@property (nonatomic,copy) myBlock block;

@end

@implementation LJTestViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.block = ^(NSString *name){
        NSLog(@"%@",self);
    };
    
}

@end

这种情况很明显了(PS:Xcode会有提示😶),因为在控制器持有的block中使用了self,所以block内部持有控制器本身,由此导致了循环引用,解决方法也很简单,设置一个弱引用即可。同时此时block存在的时候,self也必定存在,所以不需要判断是否为nil.

2)
#import "LJTestViewController.h"
#import "Person.h"
@interface LJTestViewController ()

@property (nonatomic,copy) myBlock block;

@property (nonatomic,strong) Person *p;
@end

@implementation LJTestViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.block = ^(NSString *name){
        NSLog(@"%@",_p);
    };
    
}


@end

这种情况Xcode同样会给出提示的,其实和上一种是一样的情况,虽然看上去block内部没有持有self,但其实编译器读的时候把_p 转为self->p,这样其实就相当于持有了self。解决方案可以在block外部用一个局部变量指向_p,block内部使用声明的局部变量即可。

3)
#import "LJTestViewController.h"
#import "Person.h"
@interface LJTestViewController ()
@property (nonatomic,copy) myBlock block;


@property (nonatomic,strong) Person *p;
@end

@implementation LJTestViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    Person *p = [Person new];
    p.block = ^(NSString *name) {
        self.title = name;
    };
    
    self.p = p;

}

@end

这种情况就有点隐蔽了,因为此时Xcode并没有提示了;其实他和前面两种情况也是类似的,只不过经过中间一次赋值,但达到的效果还是一样的。一般的我们开发中的循环引用我想大概基本上都是由于这种情况造成的。但解决方案还是和之前一样。所以当某个对象持有block的时候或者某个对象的对象持有block的时候,此时如果该block内部有使用了最前面的那个对象那么此时就会出现循环引用:

屏幕快照 2017-03-01 下午3.27.11.png

解决方案如下:

    __weak typeof(self) weakSelf = self;
    self.block = ^(NSString *name) {
        __strong typeof(weakSelf) strongSelf = weakSelf;  // 防止self为nil
        if (strongSelf) { // 此时strongSelf也有可能为nil
            NSLog(@"%@",strongSelf);
        }
    };
4)
#import "LJTestViewController.h"

@interface LJTestViewController ()

@property (nonatomic,strong) id<NSObject> observer;
@end

@implementation LJTestViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    self.observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"someNotification" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
        NSLog(@"%@",self);
    }];


}

- (void)dealloc {
    NSLog(@"dealloc");
    [[NSNotificationCenter defaultCenter] removeObserver:self.observer];
}

@end

这个是最近刚发现的一个循环引用,当用到带block的通知的时候,如果block中使用了self,需要用弱指针指向;否则会导致控制器无法销毁。具体原因并不清楚,如果各位有相关的资料或者合理的解释,可以随时联系我。

最后)
   [UIView animateWithDuration:5 animations:^{
        // some animation code
        self.view.backgroundColor = [UIColor orangeColor];
    }];
   [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        self.view.backgroundColor = [UIColor orangeColor];
    }];
   dispatch_async(dispatch_get_global_queue(0, 0), ^{
        self.view.backgroundColor = [UIColor orangeColor];
    });

类似上面的系统API中的block中引用到self的情况并不会造成循环引用,因为此时block没有被self所持有,所以在block中使用self是不会发生什么问题的。

相关文章

  • 【Tips】 拒绝循环引用

    前言 最近项目中检查是否有内存泄露,发现大部分的情况都是由于block的循环引用而导致的内存泄露,所以借此机会来记...

  • 4-8 循环引用

    3种循环引用 自循环引用 相互循环引用 多循环引用 Block的循环引用 NSTimer 的循环引用 破除循环引用...

  • 循环引用的相关问题

    1、循环引用的种类(1)自循环引用(2)相互循环引用(3)多循环引用 如何破除循环引用?(1)避免产生循环引用(2...

  • iOS 内存管理面试题(循环引用)

    循环引用 循环引用的实质:多个对象相互之间有强引用,不能释放让系统回收。 如何解决循环引用? 1、避免产生循环引用...

  • 内存管理-循环引用

    三种类型循环引用 自循环引用 相互循环引用 多循环引用 自循环引用 假如有一个对象,内部强持有它的成员变量obj,...

  • iOS 循环引用

    1. 循环应用的分类: 自循环引用; 相互循环引用; 多循环引用; 自循环引用: 一个对象中有一个成员变量A; 如...

  • iOS开发 循环引用的几种场景

    delegate 循环引用如果delegate使用strong修饰容易引起循环引用 block 循环引用block...

  • Day2

    1 单方向的引用不会产生循环引用。循环引用:闭包引用了self,self引用了闭包。Swift推荐使用解决循环引用...

  • 避免Block的循环引用

    避免Block的循环引用 什么是循环引用,什么时候发生循环引用 1 循环引用就是当self 拥有一个block的...

  • iOS基础 Block解决循环引用

    block 循环引用循环引用 A对象持有B,B又持有A,互相强引用 解决循环引用问题:ARC 和MRC ARC:...

网友评论

    本文标题:【Tips】 拒绝循环引用

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