#ARC 的规则非常简单:只要还有一个变量指向对象,对象就会保持在内存中。当指针指向新值,或者指针不再存在时,相关联的对象就会自动释放。
#strong修饰的对象 默认所有实例变量和局部变量都是Strong指针.它们能够保持对象的生命.
#被strong指针指向的都不会被释放.否则立刻释放,不用等爱runloop结束.所有strong指针变量不需要在dealloc中手动设为nil,ios会自动处理,debug可以看到全部被置为nil,最先声明的变量最后调用dealloc释放。
#weak型的指针变量仍然可以指向一个对象,但不属于对象的拥有者
#如果原先被指向的对象没有拥有者之后,就会被释放.就是弱引用
**为什么会出现Block循环引用的问题**
** 实际上跟IOS内存管理机制有关.**
** iOS内部计数器会管理每个对象的内存释放. 在代码中,我们的很多行为会导致Block的copy. 而当Block被copy时,会对Block中用到的对象产生强引用(arc下)或者引用计数加一(non-ARC)下.
**
@property(nonatomic, readwrite, copy) completionBlock completionBlock;
//========================================
**对象有一个Block属性,然而这个Block属性中又引用了对象的其他成员变量,那么就会对这个变量本身产生强引用,那么变量本身和他自己的Block属性就形成了循环引用**
self.completionBlock = ^ {
if (self.success) {
self.success(self.responseData);
}
};
Block 避免循环引用
__weak typeof(self) weakSelf = self;
[self doSomeBlockJob:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if(strongSelf){
...
}
}
__weak typeof(self) weakSelf = self的含义
__weak typeof(self) weakSelf = self; 实际上就等于__weak selfClass weakSelf = self;
typeof(self) 就是当前self 的class.
如果将typeof用于表达式,则该表达式不会执行。只会得到该表达式的类型。
弱引用的几种写法
__weak __typeof(&*self)weakSelf = self;
__weak __typeof(self) weakSelf = self;
__weak XxxViewController *weakSelf = self;
__weak id weakSelf = self;
@weakify(self);
@strongify(self);
##这种是ReactiveCocoa第三方插件里的内容 用到了Rac编程
问题1:使用Block的时候,为了避免产生循环引用,通常需要使用weakSelf和strongSelf.那么请问:什么时候在block里面使用self.不需要使用 weak self?
当blcok本身不被self持有,而被别的对象持有,同时不产生循环引用的时候,就不需要使用weak self了.最常见的代码就是UIView的动画代码.我们在使用UIView的 animateWithDuration:animations
方法做动画时,并不需要使用weakSelf,因为引用持有的关系是:
--UIView的某个负责动画对象持有了blocl
--block持有了self
因为self并不持有block,所以就没有循环引用的产生.
[UIView AnimateWithDuration:0.2
animation:^{
self.alpha = 1;
}
];
动画结束后,UIView会结束持有这个block,如果没有别的对象持有block的华,block对象就会释放掉,从而block会释放掉对于self的持有.整个内存关系解除.
问题2:我们知道,在使用block的时候,为了避免产生循环引用,通常需要使用weakSelf和strongSelf. 那么请问: 为什么block里面还需要写个strong self,如果不写会怎么样?
在block里面先写一个strong self. 其实是为了避免在block的执行过程中,突然出现self被释放的尴尬情况.通常情况下,如果不这么做,还很容易出现一些奇怪的逻辑,甚至闪退.
我们以AFNetworking中 AfNetworkReachabilityManager.m
的一段代码举例
__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AfNetworkReachabilityStatus status){
__strong __typeof(weakSelf) strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status;
if(strongSelf.networkReachabilityStatusBlack){
strongSelf.networkReachabilityStatusBlock(status);
}
}
如果没有strongSelf的那行代码,那么后面的每一行代码执行时,self都可能被释放掉.
在block里用strong引用,保证了持有引用的周期只在block被执行时,闭包函数返回后就释放掉.而直接使用强引用,持有引用的周期则是block的生命周期,就会引起循环引用.
问题3: block什么时候需要构建循环引用. 如果有,请举一个例子并解释这种情况下如何解决循环引用的问题.
需要不使用weak self的场景: 你需要构建一个循环引用,以保证引用双方都存在. 比如你又一个后台任务(持续监听),希望任务执行完成后,通知另一个实例.
在YTKNetwork库中,每个网络请求API会持有回调的block,回调的block会持有self,而如果self也持有网络请求API的话,我们就构造了一个循环引用.虽然我们构建出了循环引用,但是因为在网络请求结束时,网络请求API会主动释放对block的持有,因此,整个循环链条被解开,循环引用就被打破了,不存在内存泄露的问题.
- (void) clearCompletionBlock{
//nil out to break the retain cycle.
self.successCompletionBlock = nil;
self.failureCompletionBlock = nil;
}
总结来说,解决循环引用问题主要有两个办法:
1.[ 事情避免 ] , 在产生循环引用的地方使用weak若引用,以避免产生循环.
2.[ 事后补救 ], 我们明确知道会存在循环引用,但是我们在合理的位置互动断开环中的一个引用.使对象回收.
问题4:weak的内部实现原理.weak变量在引用计数为0时,会被自动设置成nil.这个特性是如何实现的.
简单来说,系统有一个全局的CFMutableDictionary
实例,来保存每个对象的weak指针列表,因为每个对象可能有多个weak指针,所以这个实例的值是 CFMutableSet
类型.
剩下我们要做的,就是在引用计数变成0的时候,去这个全局的字典里面,找到所有的weak指针,将其值设置喂nil.如何做到这一点呢? 运行时.(runtime和KVO).
当对象存在weak指针时,我们可以将这个实例指向一个新创建的子类,然后修改这个子类的release方法,在release方法中,去从全局的CFMutableDictionary
字典中知道所有weak对象,并且设置成nil.
问题5:自己写的view成员,应该用weak还是strong?
我们知道,从storyboard往编译器拖出来的UI控件的属性是weak的.
@property(weak,nonatomic) IIBOutlet UIButton *myButton;
那么,若果有些UI控件我们要用代码的方式来创建,那么它应该用weak还是strong呢?为什么?
1.这个题目是没有标准答案的.
2.storyboard拖出来的UI控件使用weak 并不是喂了规避出现循环引用的问题.
因为除非你特殊的操作view成员,viewController.view的生命周期和viewController是一样的.
在这种情况下,其实UI控件是不是weak其实关系不大.
当UI控件是weak时,它的引用计数是1,持有它的是它的superview.当UI控件是strong时,它的引用计数是2,持有它的有两个地方,一个是它的superview,另一个是这个strong的指针.UI控件并不会持有别的对象,所以,不管是手写代码还是stryboard,UI控件是strong都不会有循环引用.
3.回到最初的问题,之际写的view成员,应该用weak还是strong? 我个人觉得应该用strong,因为用weak并没有什么特别的优势,weak变量会有额外的系统维护开销,如果你没有使用它的特别的理由,那么用strong的话应该更好.
如果没要用weak,其实也没有什么问题,只需要注意在赋值之前,先把这个兑现够用addSubView加到父view上,否则可能刚刚创建完,它就被释放了.
问题6:为什么懒加载的时候必须用strong.
是因为,如果用了weak,过了懒加载就被释放了,没有被强引用.