iOS循环引用

循环引用的理解:objective-c中内存管理是机遇引用计数实现的。循环引用是指两个对象互相retain对方,通过objectice-c的release无法销毁这两个对象。
举例说:创建俩个对象A和B,现在引用计数都是1,现在A引用B,B同时也引用A,这样A和B的引用计数都是2,当调用[A release]此时A的引用变为1;[B release]此时B的引用计数为1,虽然已经都释放了,但是A和B的引用计数都是1,因为他们互相引用了,这时A和B是无法释放的。想要释放A就必须释放B,而要释放B,必须也要先释放A,所以造成这两个对象在内存中不被释放。这就是循环引用问题。
引用作者@Crayondeng文章中的例子:

- (void)loadView
{
  [super loadView];

  _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
                                                                object:nil
                                                                 queue:nil
                                                            usingBlock:^(NSNotification *note) {
      [self dismissModalViewControllerAnimated:YES];  
  }];
}
- (void)dealloc
{
  [[NSNotificationCenter defaultCenter] removeObserver:_observer];
}

这段代码中涉及到的对象包括:notificationcenter, _observer, block, self.
a) 在消息通知 block 中引用到了 self,所以这里 self 对象被 block retain;而 _observer 又对该 block 进行retain,通知中心 notificationcentre 又持有 _observer。因此只要 _observer 对象还没有被解除注册,block 就会一直被持有,从而 self 就不会被释放,那么 dealloc 就不会被调用。而我们却又期望在 dealloc 中通过 removeObserver 来解除注册以消除通知中心 notificationcenter 对 _observer 的 retain。
小结:notificationcenter –> _observer –> block –> self 只有在 self 释放,dealloc 调用的时候,notificationcenter 才会释放 _observer,显然其中存在循环引用。

b) 同时,_observer 是在 self 所在类中定义赋值,因此是被 self retain 的,这样就形成了循环引用。
小结: self –> _observer –> block –> self 显然这也是一个循环引用。
解决方案
1)Weak-Strong Dance
对于在block中的retain cycle,在2011 WWDC Session #322 (Objective-C Advancements in Depth)有一个解决方案weak-strong dance,很漂亮的名字。其实现如下:

- (void)dealloc
{
  [[NSNotificationCenter defaultCenter] removeObserver:_observer];
}

- (void)loadView
{
  [super loadView];

  __weak TestViewController *wself = self;
  _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
                                                                object:nil
                                                                 queue:nil
                                                            usingBlock:^(NSNotification *note) {
      TestViewController *sself = wself;
      [sself dismissModalViewControllerAnimated:YES];
  }];
}

在 block 使用 self 之前先用 __weak 修饰 self 创建一个 self 弱引用变量 ,然后在 block 中使用 self 之前先用 __strong 修饰创建一个 对该弱引用 self 的强引用,防止 self 被提前释放。
这样的话就可以打破循环引用了。

当然,__weak 和 __strong 只在 ARC 情形下有效;对于非 ARC ,就需要用到 __block 了,效果相同,如下:

- (void)dealloc
{
  [[NSNotificationCenter defaultCenter] removeObserver:_observer];
  [_observer release];

  [super dealloc];
}

- (void)loadView
{
  [super loadView];

  __block TestViewController *bself = self;
  _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
                                                                object:nil
                                                                 queue:nil
                                                               ngBlock:^(NSNotification *note) {
      [bself retain];
      [bself dismissModalViewControllerAnimated:YES];
      [bself release];
  }];
}

2)ReactiveCocoa中的Weak-Strong Dance

@weakify(self); 
[RACObserve(self,photosArray) subscribeNext:^(id x){
    @strongify(self);
    [self.collectionView reloadData];
}];

译注:RACObserver 是一个宏定义,有两个参数:an object and a key path on that object。当 object key path value 变化时,就会返回一个 signal。
我们对这个 signal 进行订阅,一旦 photoArray 属性发送变化,返回signal,就可以 reload collection view。

The weakify/strongify dance is all too common in Objective-C under ARC.Weakify creates a new, weak variable assigned to self. Strongify then creates a new, strong variable in its scope assigned to the weak self. When strongify does this, it’s using what’s called a “shadow variable” – so named because the new, strong variable is called self, replacing the former strong reference to self.

Basically, the subscribeNext: block is going to capture self in its lexical scope, causing a reference cycle between self and the block. The block is strongly referenced by the return value of subscribeNext:, a RACSubscriber instance. This is then captured by the RACObserver macro, which will be automatically deallocated once its first parameter, self is deallocated. Without the weakify/strongify invocations, self would never be deallocated.
译注:分析一下其中可能存在的 block 循环引用问题。
self –> RACObserver macro –> RACSubscriber instance –> block –> self. 假如不使用 weakify/strongify 那么现实其中的循环引用导致 self 始终无法释放。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值