2015-10-06 128 views
1

考虑我在我的视图控制器中,我添加了Singleton属性的RACObserve,并且在subscribNext中我有一个自引用。 的代码如下:为什么此RACObserve块导致保留循环?

[RACObserve([Singleton shared], singletonFlag) subscribeNext:^(NSNumber *singletonFlag) { 
     self.flag = [singletonFlag boolValue]; 
    }]; 

根据我的理解,自己不持有块的强引用(而块持有强烈的自我参照),这应该不会造成保留周期。 我已阅读反应可可的内存管理以及https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/Documentation/Legacy/MemoryManagement.md 在他们提供一个例子作为

[RACObserve(self, username) subscribeNext:^(NSString *username) { 
    [self validateUsername]; 
}]; 

我完全理解为什么它造成上述情况下的保留周期,我们需要的块内弱的自我。 我很困惑,为什么在第一种情况下,它会导致一个保留周期。为了确认这一点,只需将该代码片段粘贴到viewDidLoad后面,并查看视图控制器是否应该在何时解除分配。 如果你需要看到单身的多个实现,这是代码,

@interface Singleton : NSObject 
@property (readwrite,nonatomic) BOOL singletonFlag; 
@end 

@implementation Singleton 
+ (Singleton *)shared { 
    static dispatch_once_t pred = 0; 
    __strong static id _sharedObject = nil; 
    dispatch_once(&pred, ^{ 
     _sharedObject = [[self alloc] init]; 
    }); 
    return _sharedObject; 
} 

- (id)init { 
    if (self = [super init]) { 
     NSLog(@"init of %@",NSStringFromClass(self.class)); 
    } 
    return self; 
} 
@end 

任何赐教这件事吗?

+1

它不是一个真正的循环,但单永远不会被释放,由于是单身,所以对你的视图控制器持有强烈的参考的块永远不会放弃那个参考。 – dan

+0

@dan为什么不作为回答发布? :) – mattsson

+0

感谢@dan我想我现在得到它,这意味着这个subscribeNext块不像我们的正常定义的块(这是block执行后dealloc),我是否正确地说? –

回答

4

内部实现相当复杂,是否存在真正的保留周期并不重要。

这里为什么内存泄漏是只在你的两个实施例中的相同的原因:

  1. self
  2. 的块通过
  3. 订户被保持内部订户对象保持的块保留通过RACObserve信号的一些内部信息直到信号终止。
  4. 当目标(单实例实例)或self(RACObserve微内存使用self)被释放时,RACObserve信号终止。

但是现在单例实例不会释放,并且self也不会释放,因为它已经被保留了。所以信号永远不会终止,然后内存泄漏。

0

无论如何,你应该写这样的事情

[RACObserve([Singleton shared], singletonFlag) subscribeNext:^(NSNumber *singletonFlag) { 
    self.flag = [singletonFlag boolValue]; 
}]; 

相反,写

RAC(self, flag) = RACObserve([Singleton shared], singletonFlag);