Wednesday, 22 October 2014

removeFromParentViewController - do you need to nil afterwards?

Can a child view controller "dismiss itself?" .....

You have a view controller "RedMessage". You have an ordinary strong property for it ...
@property (strong) RedMessage *red;
You add it ("modally") on top of your current VC...
self.red = (RedMessage *)[self.storyboard
     instantiateViewControllerWithIdentifier:@"RedMessageID"];
self.red.view.frame = self.view.frame;
[self.view addSubview:self.red.view];
[self addChildViewController:self.red];
[self.red didMoveToParentViewController:self];
To get rid of it later, do this
[self.red willMoveToParentViewController:nil];
[self.red.view removeFromSuperview];
[self.red removeFromParentViewController];
BUT IN FACT, do you need to do this??
[rm willMoveToParentViewController:nil];
[rm.view removeFromSuperview];
[rm removeFromParentViewController];
rm = nil;
Do you need the "= nil;" ?
Note that this question is critical, because: if you do NOT HAVE TO nil it, you can then do the followinginside the new view controller...
-(void)dismissMyselfCompletely
    {
    [self willMoveToParentViewController:nil];
    [self.view removeFromSuperview];
    [self removeFromParentViewController];
    }
Which is extremely convenient.
In short, if you do that inside the new top view controller - will it "work", does it release the VC?
When removeFromParentViewController happens, does the parent VC understand it can release self.red?

Ans))  

you can in fact allow a VC to "remove itself."

it does go away and is not retained.
We add the VC on top like this (just in the usual way you add a "modal" VC on top...)
-(void)showOverlay:(NSDictionary*)dict
    {
    Red *rr = (Red *)[self.storyboard
        instantiateViewControllerWithIdentifier:@"RedID"];
    rr.view.frame = self.view.bounds;
    [self.view addSubview:rr.view];
    [self addChildViewController:rr];
    [rr didMoveToParentViewController:self];

    [rr useThisData:dict];
    }
Note that there's no Property holding rr - it is just created and added on the fly in that category.
Inside "Red" we get rid of it just like this...
-(void)dismiss:(UITapGestureRecognizer *)sender
    {
    [self.view exitLeftSmoothly:0 then:^
        {
        [self willMoveToParentViewController:nil];
        [self.view removeFromSuperview];
        [self removeFromParentViewController];
        }];
    }
(exitLeft is just an animation, not relevant)
Finally you can test it like this:
-(void)viewDidAppear:(BOOL)animated
    {
    [super viewDidAppear:animated];
    ....
    [self _teste];
    }

-(void)_teste
    {
    Red __weak *mySelf = self;
    dispatch_after_secs_on_main(0.5, ^
        {
        NSLog(@"tick !!!!!!!!!!!!");
        if ( mySelf == nil ) NSLog(@"I no longer exist - WTF!");
        [mySelf _teste];
        });
    }
You can see clearly that once the "Red" vc is dismissed, indeed, the ticker stops running: "Red" has gone away.
It does seem to work reliably. Your output will look something like this...
2014-10-22 17:26:36.498 [1738:111092] tick --- !!!!!!!!!!!!
2014-10-22 17:26:37.031 [1738:111092] tick --- !!!!!!!!!!!!
2014-10-22 17:26:37.576 [1738:111092] tick --- !!!!!!!!!!!!
2014-10-22 17:26:38.124 [1738:111092] tick --- !!!!!!!!!!!!
2014-10-22 17:26:38.674 [1738:111092] tick --- !!!!!!!!!!!!
2014-10-22 17:26:39.217 [1738:111092] tick --- !!!!!!!!!!!!
2014-10-22 17:26:39.764 [1738:111092] tick --- !!!!!!!!!!!!
2014-10-22 17:26:39.764 [1738:111092] I no longer exist --- WTF!
To reiterate, as AnujYadav points out, if you use a property in the parent VC for the "Red"...
@property (strong) Red *red;
then
self.red = (Red *)[self.storyboard
 instantiateViewControllerWithIdentifier:@"RedID"];
etc ... indeed this DOES NOT work. In that case, you would have to self.red=nil in the parent, or it will not go away.

No comments:

Post a Comment