【问题标题】:why this RACObserve block caused retain cycle?为什么这个 RACObserve 块会导致保留周期?
【发布时间】:2016-01-03 14:19:22
【问题描述】:

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

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

根据我的理解,self 不持有块的强引用(而块持有 self 的强引用),这不应该导致保留循环。 我也读过反应可可的内存管理https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/Documentation/Legacy/MemoryManagement.md 他们在其中提供了一个示例

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

我完全理解为什么它会导致上述情况下的保留循环,我们需要在块内有一个弱自我。 我很困惑为什么在第一种情况下会导致保留周期。要确认这一点,只需在 viewDidLoad 之后粘贴该代码 sn-p 并查看视图控制器是否在应有的时候被释放。 如果您需要查看更多单例的实现,这就是代码,

@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

有人告诉我这个吗?

【问题讨论】:

  • 这不是一个真正的循环,但由于是单例,单例永远不会被释放,因此持有对视图控制器的强引用的块永远不会放弃该引用。
  • @dan 为什么不将其发布为答案? :)
  • 谢谢@dan 我想我现在明白了,这意味着这个 subscribeNext 块不像我们正常定义的块(在块执行后是 dealloc),我这样说对吗?

标签: ios objective-c reactive-cocoa


【解决方案1】:

内部实现相当复杂,是否有真正的retain循环并不重要。

这两个例子中内存泄漏的原因是一样的:

  1. self 被区块保留
  2. 块由内部订阅者对象保留
  3. 订阅者被 RACObserve 信号的某些内部事物保留,直到信号终止。
  4. 当目标(单例实例)或self(RACObserve 微隐式使用self)被释放时,RACObserve 信号终止。

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

【讨论】:

    【解决方案2】:

    无论如何,你不应该写这样的东西

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

    改为写

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

    【讨论】:

      【解决方案3】:

      问题在于 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 方法杀死它才能摆脱它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-19
        • 2015-03-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-21
        相关资源
        最近更新 更多