避免循环引用


ARC转换总结+避免循环引用

字数970  阅读227  评论0 

参考

上面的文章写得已经非常全面了,不过还是有些东西需要补充一下。

循环引用

循环引用和ARC没有直接关系,但是在转换的过程中遇到了相关问题,所以就着重说明一下。

循环引用的原因

任何一种语言,都必须有它的内存管理方式。比如C语言中,我们用malloc申请一块内存,放入数据。当这块内存不在需要时,就调用free将其释放掉。这是一种比较原始的方式,当同一块内存在多个地方被用到时,到底应该由谁来释放呢?你只能小心翼翼的处理这种问题,除此之外没有别的办法。

Objective-C相较于C的一大优势就是内存管理,提出了引用计数的概念。引用计数是针对对象的,即NSObject,不是NSObject就没必要谈引用计数。

在Objective-C中,凡是继承自NSObject的类都提供了两个方法,retain和release。当我们调用一个对象的retain时,这个对象的内存计数加1;反之,当我们调用release时, 对象的内存计数减1,只有当对象内存计数为0时,这个对象才真正会被释放,此时,对象的delloc方法会自动被调用,来做些内存回收前的工作。

那么问题就来了。比如有A和B两个对象,A持有B,B同时也持有A,按照上面的规则,A只有B释放之后才有可能释放,同样B只有A释放后才可能释放,当双方都在等待对方释放的时候, 循环引用就形成了。两个对象都永远不会被释放,这样就造成内存泄露。

//ARC code
@interface A : NSObject

@property (nonatomic,strong) B* b;

@end

@interface B : NSObject

@property (nonatomic,strong) A* a;

@end

解决办法也很简单,只要不让A和B同时保持对方的强引用即可。 注意,B对A的引用是weak。知道为什么我们要把Delegate对象设成weak了吧?

//ARC code
@interface A : NSObject

@property (nonatomic,strong) B* b;

@end

@interface B : NSObject

@property (nonatomic,weak) A* a;

@end

当Block遇到ARC

Block的概念这里就不详细解释了。我想说的是,Block就是一个对象,它能访问上下文变量,这就要保证上下文所属的对象在Block运行时必须不被释放,所以Block默认会对当前上下文进行强引用。这时如果当前对象也对Block有强引用,那么就会造成循环引用。比如下面的代码,self强引用tableView,tableView强引用block;block又强引用self,所以问题就产生了。

 [self.tableView addPullToRefreshWithActionHandler:^{
        self.isRefresh = YES;
        self.hideHud = YES;
        self.currentPage = 0;
        [self queryCarFault];
    }];

如何破局,ARC之后有一个__weak的关键字。这样Block就不会强引用BBWarningRecordTableViewController的对象了。

__weak BBWarningRecordTableViewController* weakSelf = self;
    [self.tableView addPullToRefreshWithActionHandler:^{
        weakSelf.isRefresh = YES;
        weakSelf.hideHud = YES;
        weakSelf.currentPage = 0;
        [weakSelf queryCarFault];
    }];

从上面的代码可以看到,我们只是加了一行代码

__weak BBWarningRecordTableViewController* weakSelf = self;

但是有一次我发现类似的语句不止一种写法

// 不知道这行代码的使用场景的同学你该去自习看看ARC的注意事项和Block的使用了
// AFNetworking的写法
__weak __typeof(&*self)weakSelf = self;

// 我之前一直这么写的
__weak __typeof(self) weakSelf = self;
// 或者这么写
__weak XxxViewController *weakSelf = self;
// 或者这么写
__weak id weakSelf = self;

这四种写法居然都是对的,第三种在我看来是最不好的,因为每个地方都要单独写。而其余几种写法都可以封装成一个宏,当项目中很多地方都要写类似代码时,用宏肯定是最佳的实践。


###############

http://www.jianshu.com/p/66e900f733b2

为什么需要weakSelf?



*********************************

iOS中@strongify和@weakify的使用场景和原理?


主要是在block中使用

因为block一般都在对象内部声明.. 如果在block内部使用了当前对象的属性,就会造成循环引用(block拥有当前对象的地址,而当前对象拥有block的地址),而引起内存泄露,block和当前对象都无法释放.

@weakify 将当前对象声明为weak.. 这样block内部引用当前对象,就不会造成引用计数+1可以破解循环引用

@strongify 相当于声明一个局部的strong对象,等于当前对象.可以保证block调用的时候,内部的对象不会释放

大概相当于

 
 
__weak __typeof(self)weakSelf = self; block = ^(){ __strong __typeof(weakSelf)strongSelf = weakSelf; // strongSelf.property };


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值