Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 following inside 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?

like image 619
Fattie Avatar asked Oct 12 '14 12:10

Fattie


3 Answers

After considerable testing, we found that it appears to be the case that:

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.

like image 123
Fattie Avatar answered Nov 15 '22 19:11

Fattie


This is more memory management question than view controller containment one. No you don't need to put nil there, but...

You are assuming that you have a reference to it. Question is: is it strong reference? if yes, than you have to nil it, because that view controller will not be dellocated. Easiest way to test it is to add -dealoc method to rm with log message.

like image 43
Juraj Antas Avatar answered Nov 15 '22 17:11

Juraj Antas


There seems to be a difference in your question and answer. In your overlay method (in answer) you did not assigned the ViewController to any strong property and in question you have strong property. I have not tested the code but I feel you should update your test to have a strong property.

I think ideally we should "nil" the property. Otherwise, from stack yes view controller will be removed.

like image 41
Anuj Yadav Avatar answered Nov 15 '22 18:11

Anuj Yadav