ARC strong和weak


#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,过了懒加载就被释放了,没有被强引用.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,099评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,828评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,540评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,848评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,971评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,132评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,193评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,934评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,376评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,687评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,846评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,537评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,175评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,887评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,134评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,674评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,741评论 2 351

推荐阅读更多精彩内容