Recently after following Apple documentation
I used the following conventions to avoid retain cycle issues.
__weak __typeof(self) weak_self = self;
void(^completionBlock)(void) = ^(){
__typeof(self) strong_self = weak_self;
if (strong_self) {
if (strong_self->_completion != NULL) {
strong_self->_completion();
}
}
};
But this code is found to be crashing because self is getting deallocated before invoking the block.
When I used the following it is found to be working.
__block __typeof(self) block_self = self;
void(^completionBlock)(void) = ^(){
if (block_self->_completion != NULL) {
block_self->_completion();
}
};
Now I am confused when we should use __weak reference. Only in the following case of "self.completionBlock"
__weak __typeof(self) weak_self = self;
self.completionBlock = ^(){
if (weak_self->_completion != NULL) {
weak_self->_completion();
}
};
Any light on this conditions will be very useful to me.
My implementation code is given below.
=================================================
File MyViewController
#implementation MyViewController
//starting point
- (void)myPushMethod {
__weak __typeof(self) weak_self = self;
MyViewControllerTransitioning *delegateObj = [[MyViewControllerTransitioning alloc] initWithCompletion:^{
//resetting the delegate
__typeof(self) strong_self = weak_self;
if (strong_self) {
strong_self.navigationController.delegate = nil;
}
}];
self.navigationController.delegate = delegateObj;
[self.navigationController pushViewController:someViewController animated:_animated];
//it is found that delegateObj is getting deallocated while reaches this point
}
#end
=================================================
File MyViewControllerTransitioning
#implementation MyViewControllerTransitioning
- (instancetype)initWithCompletion:(completionHandler)completionHandler
{
if(self = [super init])
{
if (completionHandler != NULL) {
_completion = completionHandler;
}
}
return self;
}
- (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC
{
id<UIViewControllerAnimatedTransitioning> animationTransitioning = nil;
//crashes here
__block __typeof(self) block_self = self;
void(^completionBlock)(void) = ^(){
if (block_self->_completion != NULL) {
block_self->_completion();
}
};
//showing presentation-up animation if Push
if (operation == UINavigationControllerOperationPush) {
animationTransitioning = [[MyAnimator alloc] initWithAnimationCompletion:completionBlock];
}
return animationTransitioning;
}
- (void)dealloc{
//dealloc is called before invoking completionBlock
}
#end
=================================================
File MyAnimator
#implementation MyAnimator
- (instancetype)initWithAnimationCompletion:(presentationUpCompletion)completionHandler
{
if(self = [super init])
{
if (completionHandler != NULL) {
_completion = completionHandler;
}
}
return self;
}
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return my_duration;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
//animation logic
[UIView animateWithDuration:duration animations: ^{
//animation logic
} completion: ^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
- (void)animationEnded:(BOOL) transitionCompleted {
if (transitionCompleted && _completion != NULL) {
_completion();
}
}
#end
In my original answer, below, I walk through the standard weakSelf pattern (and the weakSelf-strongSelf "dance"). My conclusion was that presentation slide you reference is absolutely correct regarding the weakSelf pattern (though that presentation is stylistically dated).
You subsequently provided a more complete code sample, and it turns out that it suffers from a different, unrelated problem. (Worse, it was a problem that only manifests itself when the strong reference cycles are resolved. lol.) Bottom line, the code sets the delegate of the navigation controller to a local object which falls out of scope. Because the navigation controller doesn't retain its delegate, you were ending up with a dangling pointer to this deallocated object.
If you keep your own strong reference to this delegate object (keeping it from being deallocated), the problem goes away.
My original answer is below.
You said:
used the following conventions to avoid retain cycle issues.
__weak __typeof(self) weak_self = self;
void(^completionBlock)(void) = ^(){
__typeof(self) strong_self = weak_self;
if (strong_self) {
if (strong_self->_completion != NULL) {
strong_self->_completion();
}
}
};
But this code is found to be crashing because self is getting deallocated before invoking the block.
No, this is a very common pattern (often jokingly called the "weak self, strong self dance"). There is nothing wrong with this. If it's crashing, it's for other reasons.
Sure, I'd use modern naming conventions (weakSelf and strongSelf rather than weak_self and strong_self). And I'd remove the __ at the start of __typeof. And I wouldn't be inclined to dereference and ivar, but rather use a property. So, I might end up with something like:
__weak typeof(self) weakSelf = self;
void(^completionBlock)(void) = ^(){
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
if (strongSelf.completion != NULL) {
strongSelf.completion();
}
}
};
But, still, if that is crashing, you have some other problem. Frankly, you have a block calling a block so it's a little hard to guess where your problem rests, but the problem is not in the "weak self" pattern.
Later you go on to suggest using:
__block __typeof(self) block_self = self;
That does not do what you think it does. The goal of the "weak self" pattern is to break the strong reference cycle (formerly known as retain cycle), but in ARC, this __block reference does nothing to resolve that strong reference cycle. Note, in non-ARC code, this block_self pattern was used to break retain cycles, but it will not do the job in ARC.
Finally, you go on to suggest:
__weak __typeof(self) weak_self = self;
self.completionBlock = ^(){
if (weak_self->_completion != NULL) {
weak_self->_completion();
}
};
This has two serious problems. First, you are dereferencing a weak variable. If weak_self was nil, it would crash. Second, even if you fixed that by using property accessor methods rather than dereferencing ivars, you have another problem here, namely a race condition.
Bottom line, the "weak self" pattern from that presentation is correct. Likewise, the "weak self, strong self dance" from your first example is also correct. If it's crashing for you, you have to provide us a MCVE which reproduces the problem. But in ARC code, this is a perfectly valid pattern.
self.completionBlock
self has a strong reference to completionBlock (it's a property variable), then u need to weak reference to self to avoid the cycle.
(void)(^completionBlock)(void) = ^{}
self has NO strong reference to completionBlock (it's a local variable), no need to create a weak reference to self.
And the reason for the one you added __block works is that "__block causes the variable to be strongly referenced".
Related
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?
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 block
The block is retained by an internal subscriber object
The subscriber is retained by some internal thing of the RACObserve signal until the signal terminates.
The RACObserve signal terminates when either the target (the singleton instance) or self (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.
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);
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.
This is my code
__weak KDObject *obj = [KDObject fetchObj] ;
NSLog(#"%#", obj) ; // I think it should be nil, but it is not
obj.i = 10 ;
NSLog(#"%d", obj.i) ;
In KDObject.m
#implementation KDObject
+ (instancetype)fetchObj
{
return [[self alloc] init] ;
}
#end
the result is the same whatever KDOjbect.m is compile with -fno-objc-arc flag or without -fno-objc-arc flag
Anybody has ideas why obj is not nil ?
Related to your Q and to your answer:
-fectchObject is a method not belonging to any method family with ownership transfer. Therefore ARC has to ensure that returning the reference is safe. That means that losing the strong reference in the local scope of -fetchObject does not give up the last reference.
One way to accomplish this is to use the autorelease pool. But ARC does not guarantee that the ARP is used. Moreover it tries not to use the ARP, because it is the solution with the highest memory pressure.
So the things happening depends of the compiler implementation, attributes set to the method and what the compiler sees in source code (esp. implementation of -fetchObject). So you should not rely on returning in ARP.
__weak is guaranteed to be nil, if the object is destroyed. But it is not guaranteed that the object is destroyed in the earliest possible moment. This is subject of optimization.
From the docs about __weak
__weak specifies a reference that does not keep the referenced object alive. A weak reference is set to nil when there are no strong
references to the object.
Whether it's __weak or not KDObject *o = [[KDObject alloc] init] creates an object so o is not nil.
__weak is something realated to memory management. If none of strong objects are pointing to a weak object, it would be released from memory.
- (void)loadView
{
[super loadView];
TestObject *obj_ = [[TestObject alloc] init];
pObj = obj_;
if(pObj == nil)
{
NSLog(#"pObj_ is not nil");
}
__weak TestObject *obj2_ = [[TestObject alloc] init];
if(obj2_ == nil)
{
NSLog(#"obj2_ is nil");
}
__weak TestObject *obj3_ = [TestObject createInstance];
if(obj3_ == nil)
{
NSLog(#"obj3_ is nil");
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(pObj == nil)
{
NSLog(#"pObj is nil");
}
}
KudoCC requested this code. I used LLVM5.1. If I use -fno-objc-arc to TestObject.h, the objc3_ became not nil.
I have a Class called ServiceBrowser. Inside this class I have a block based method that searches for NSNetServices.
I call the method as such :
[_serviceBrowser discoverServicesOfType:#"_theService._tcp."
inDomain:#"local."
didDiscoverServices:^(NSArray *services) {
NSLog(#"Services discovered %#", services);
[UIView fadeView:_button toAlpha:1.0 duration:0.5 completion:nil];
} didRemoveServices:^(NSArray *services) {
NSLog(#"Services removed %#", services);
} failure:^(NSString *message) {
NSLog(#"Failure %#", message);
}];
If I remove the call to fadeView:toAlpha:duration:completion: it finds the services and logs them out. Only when I use self inside this block Xcode crashes without any error logged to the console.
fadeView:toAlpha:duration:completion: is a category method on UIView that takes a view and fades it in or out and this works fine as a standalone method. The problem is when I use _button inside the block it crashes.
I have investigated this and I assume it is down to a retain cycle. From looking at other questions and blog posts I should use a weak self inside the block.
I have tried using __block id weakSelf = self; and also typeof(self) __weak w_self = self; and neither work.
You could try to modify your class so that you pass self as method parameter and the class passes the reference back to the block:
[_serviceBrowser discoverServicesOfType:#"_theService._tcp." inDomain:#"local." didDiscoverServices:^(NSArray *services, id sender) {
// ^^^^^^^^^ "sender" is "self"
} didRemoveServices:^(NSArray *services) {
} failure:^(NSString *message) {
} fromSender:self];
// ^^^^^^^^^^^^^^^ pass self here
The implementation inside the class would be kind of:
- (void)discoverServicesOfType:(NSString *)type inDomain:(NSString *)domain didDiscoverServices:^(NSArray *, id)discoveredBlock fromSender:(id)sender {
NSMutableArray *services = [NSMutableArray array];
// do some fancy stuff here
discoveredBlock(services, sender);
}
Anc Ainu could also be right. Please check whether or not the object still exists.
You might try the following code which captures a weak reference of self within the block (Foo is the class of self).
The block also takes care now, that UIKit methods will be executed on the main thread:
__weak Foo* weakSelf = self;
[_serviceBrowser discoverServicesOfType:#"_theService._tcp."
inDomain:#"local."
didDiscoverServices:^(NSArray *services) {
NSLog(#"Services discovered %#", services);
Foo* strongSelf = weakSelf;
if (strongSelf) {
dispatch_async(dispatch_get_main_queue(), ^{
[UIView fadeView:strongSelf.button
toAlpha:1.0
duration:0.5 completion:nil];
});
}
} didRemoveServices:^(NSArray *services) {
NSLog(#"Services removed %#", services);
} failure:^(NSString *message) {
NSLog(#"Failure %#", message);
}];
Should self be deallocated when the block executes, the strong reference strongSelf will be nil.
Edit
Why is capturing a weak pointer from a UI element preferred over capturing a strong pointer? While this is likely not the cause of your crash, it is a substantial improvement.
The block below strongly captures self to demonstrate this. Note, when you reference an ivar directly e.g. _button and not via the property self.button, self will be implicitly captured in the block, that is it will be retained until after the block has finished.
Now, the effect of the block is, that the UI element self will be held alive until after the block executes, no matter when this happens and no matter if the view is visible anymore: the user might have switched to numerous other views and controllers in the meantime. However, self don't get deallocated until after the block finishes. This unnecessary holds resources in memory (possibly large images) which don't get freed up to this point.
[_serviceBrowser discoverServicesOfType:#"_theService._tcp."
inDomain:#"local."
didDiscoverServices:^(NSArray *services) {
NSLog(#"Services discovered %#", services);
dispatch_async(dispatch_get_main_queue(), ^{
[UIView fadeView:self.button
toAlpha:1.0
duration:0.5 completion:nil];
});
} didRemoveServices:^(NSArray *services) {
NSLog(#"Services removed %#", services);
} failure:^(NSString *message) {
NSLog(#"Failure %#", message);
}];
I have a block attached to a button (using this category):
__unsafe_unretained typeof(UIImage) *weakPic = originalPic;
[button addEventHandler:^{
switch (state) {
case state1:
{
UIViewController *vc = //some VC
vc.pic = weakPic; // weakPic is nil at this point
// putting originalPic here would solve my problem
// but then I would have a retain cycle
}
case state2:
{
// other stuff
}
}
}];
the action associated with the button is different depending on the state.
Here is the problem: I must keep the above __unsafe_unretained to avoid having a retain cycle. However, this code is called at a point where originalPic = nil.. and so when I assign weakPic to vc.pic I'm assigning it a nil value. If I replace weakPic with just originalPic, then it works fine.. (originalPic will have the updated value) but then I get the retain cycle.. ideas?
Without knowing more about your code I suggest you consider declaring a weakSelf and implementing an accessor on self.
//the accessor
-(UIImage*)pic{
return originalPic;
}
-(void)someSetupMethod{
__weak id weakSelf = self;
[button addEventHandler:^{
switch (state) {
case state1:
{
UIViewController *vc = //some VC
vc.pic = [weakSelf pic]; // if weakself is nil at this point, then
// originalPic is likely invalid
}
case state2:
{
// other stuff
}
}
}];
}
It may not be a weakSelf you want, but some other object. In that case just declare that other object to be weak, as long as you can be relatively sure it will exist as long or longer than the button.
You might also want to look at declaring it as a __block variable. The __block keyword prevents a copy of the object from being made inside the block.
See this thread for a better explanation of __weak and __block references.
i make a AdView extends UIView like this
AdView:
//nerver call dealloc when adview release
-(void)dealloc
{
//stop thread
bStart = NO;
//...
[super dealloc];
}
-(id)init
{
//.....
bStart = YES;
//the self will retain by NSThread,i try to call [self performBackground..:onThrad] or timer the same too.
NSThread* thead = [[NSThread alloc] initWithTagert:self ...:#select(onThread)];
[thread start];
[thread release];
}
-(void)onThread
{
while(bStart)
{
//....
}
}
the controller
{
AdView* view = [[AdView alloc] init];
view.delegate = self;// i am ture delegate is not retain
[self.view addSubView:view];
[view release]
}
Adview has never to call dealloc when contoller release,
who konws how to fix it.
As others noted you are passing self to the target initialization which retains it. That's why you have an extra retain causing the object not being deallocated.
That said, let me give you two pieces of advice here:
Use ARC. It's 2013, we suffered with manual reference counting for about enough time.
Use GCD. It's 2013, we suffered with manual threads management for about enough time.
A modern version of your code would look like
- (instancetype)init {
//...
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self doStuffAsynchronously];
});
//...
}
- (void)doStuffAsynchronously { ... }
EDIT
As JFS advices in the comments, if you need to start and stop the background execution you should consider using a NSOperation within a NSOperationQueue. A naive (but still functional) implementation would be:
#property (nonatomic, strong) NSOperationQueue * operationQueue;
//...
- (instancetype)init {
//...
self.operationQueue = [NSOperationQueue new];
[operationQueue addOperationWithBlock:^{
[self doStuffAsynchronously];
}];
//...
}
- (void)doStuffAsynchronously { ... }
- (void)stopDoingStuff {
[self.operationQueue cancelAllOperations];
}
A neater approach, though, would be to subclass NSOperation, starting it by adding it to a queue and stopping it by invoking stop.
The thread retains the target self in start. So the object can not go away as long as the thread runs.
The controller should stop the thread by calling something like adView.bStart = NO; (which of course you have to implement).