Reputation: 1337
Consider I in my view controller, I added RACObserve of property of Singleton, and inside subscribNext I have a self reference in it. The code is as below:
[RACObserve([Singleton shared], singletonFlag) subscribeNext:^(NSNumber *singletonFlag) {
self.flag = [singletonFlag boolValue];
}];
Based on my understanding, self don't hold a strong reference of the block(while block hold a strong reference of self), this shouldn't cause retain cycle. I have read memory management of reactive cocoa as well https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/Documentation/Legacy/MemoryManagement.md In which they provide an example as
[RACObserve(self, username) subscribeNext:^(NSString *username) {
[self validateUsername];
}];
I totally understand why it caused the retain cycle in above case and we need a weak self inside the block. I am confused why in the first case, it will cause a retain cycle. To confirm this, just paste that code snippet after viewDidLoad and see whether the view controller was dealloc-ed when it should be. If you need see more implementations of the singleton, this is the code,
@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
Anyone enlighten me about this?
Upvotes: 1
Views: 863
Reputation: 31
The problem is that RACObserve() will return you a RACDisposable object, that you have to dispose your self. If you use it the way RAC()=RACObserve(), then the RAC() part will take care of killing the RACDisposable object that is returned by RACObserve() method.
One quick fix that you can make when using the RACObserver like this:
[RACObserve(self, username) subscribeNext:^(NSString *username) {
[self validateUsername];
}];
Is to turn it into this: (RACDisposable *disposableSignal; declared in .h for example)
disposableSignal=[RACObserve(self, username) subscribeNext:^(NSString *username) {
[self validateUsername];
}];
And use [disposableSignal dispose] to deallocate the signal. For example in viewWillDisappear method. Basically you have to kill it with dispose method to get rid of it.
Upvotes: 0
Reputation: 10608
Anyway, you shouldn't write such things as
[RACObserve([Singleton shared], singletonFlag) subscribeNext:^(NSNumber *singletonFlag) {
self.flag = [singletonFlag boolValue];
}];
Instead, write
RAC(self, flag) = RACObserve([Singleton shared], singletonFlag);
Upvotes: 0
Reputation: 4987
The internal implementation is quite complicated, It's not important whether there is a real retain cycle.
Here the reason why memory leaks is just the same in your two examples:
self
is retained by the blockself
(the RACObserve micro is implicitly using self
) is deallocated. But now the singleton instance won't dealloc, and self
won't dealloc neither since it's already retained. So the signal never terminates, then memory leaks.
Upvotes: 4