为什么这个RACObserve阻塞引起了保留周期?

时间:2015-10-06 15:25:37

标签: ios objective-c reactive-cocoa

考虑我在我的视图控制器中,我添加了Singleton属性的RACObserve,而在subscribNext里面我有一个自引用。 代码如下:

[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

有人对此有所启发吗?

3 个答案:

答案 0 :(得分:4)

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

在这两个例子中,内存泄漏的原因是相同的:

  1. self由块
  2. 保留
  3. 该块由内部订户对象保留
  4. 用户由RACObserve信号的某些内部信息保留,直到信号终止。
  5. 当目标(单例实例)或self(RACObserve micro隐式使用self)被解除分配时,RACObserve信号终止。
  6. 但是现在单例实例不会dealloc,self也不会dealloc,因为它已经保留了。所以信号永远不会终止,然后是内存泄漏。

答案 1 :(得分:0)

无论如何,你不应该写

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

相反,写一下

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

答案 2 :(得分:0)

问题在于RACObserve()将返回一个RACDisposable对象,您必须处置自己。如果以RAC()= RACObserve()的方式使用它,那么RAC()部分将负责杀死由RACObserve()方法返回的RACDisposable对象。

使用RACObserver时可以进行的一个快速修复:

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

}];

是将其转换为: (RACDisposable * disposableSignal;例如以.h声明)

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

}];

并使用[disposableSignal dispose]解除信号分配。例如在viewWillDisappear方法中。基本上,您必须使用dispose方法将其杀死以摆脱它。