viewDidUnload - is this correct?

Discussion in 'iOS Programming' started by MACloop, Jul 5, 2010.

  1. macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #1
    Hello,
    I have struggled with this before and I hope that I have it correct now? The issue is about viewDidUnload and what variables to release, set to nit etc in this method. As I understand a memorywarning will lead to this method and afterwards the view will be loaded again. So, the variables I have released etc are all allocated or retained or IBOutlets... I have set some comments in the method inorder to show how they are retaiend/allocated.
    So, what do you think?

    Code:
    - (void)viewDidUnload {
    	[self.theStringInfoArray release];//is allocated in the init method, has a property with assign in .h-file
    	[self.locManager release];/is allocated in the init method, has a property with assign in .h-file
    	[self.infoPopoverController release];/is assigned in the viewDidLoad method, has a property with retain in .h-file
    	[startMap release];//is a IBOutlet with a property retain
    	theLoader = nil;//is a IBOutlet with no property, is not retained or alloced in the class - only used like [theLoader stopAnimating]
    }
    
    - (void) dealloc {
            [theStringInfoArray release];
    	[locManager release];
    	[infoPopoverController release];
    	[startMap release];
    	[theLoader release];
    	[super dealloc];
    }
    
    Thanks in adevance!
    MACloop
     
  2. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    You should not release any object twice unless you have retained it twice (counting alloc/init as a retain). If you release the object in viewDidUnload what will happen in dealloc?
     
  3. thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #3
    Ok, now I am confused :confused:

    I thought that in case of a memorywarning the ViewDidUnload method is called and the dealloc is never called in this case. After the objects/variables are released or set to nil in the viewDidUnload, the view will be loaded again ie viewDidLoad is called again to load the view... If dealloc is called when a memory warning is sended...why does viewDidUnload excist at all...?

    MACloop
     
  4. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    viewDidUnload will be called when the view unloads.
    dealloc will be called when the view controller itself reaches retain count 0 and is removed from memory. In your application it may be that dealloc is never called, but I would not count on that being the case.
     
  5. thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #5
    OK, what would you suggest in the case above? Only to set variables being IBOutlets to nil? I mean, if I alloc the variables again in the viewDidLoad method, there will be a leak... Could a solution be to check in the viewdidload if the varaible is nil and if it is - allocate it?

    MACloop
     
  6. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #6
    I would set the properties to nil in viewDidUnload, reload them in viewDidLoad and check if they were non-nil and if they were set them to nil in dealloc (in case the view controller somehow reaches retain count 0 without viewDidUnload being called).

    I would also note that this:
    Code:
    [self.theStringInfoArray release];
    
    is potentially very unwise. If theStringInfoArray is defined as something like:
    Code:
    @property (retain) NSArray *theStringInfoArray;
    
    then after your release this would print "non-nil":
    Code:
    if (self.theStringInfoArray!=nil)
    {
    NSLog(@"non-nil");
    }
    
    Clearly this can/will lead to crashes. You should not ever leave dangling pointers like this. The correct thing to do is:
    Code:
    self.theStringInfoArray = nil;
    
    This will call the setTheStringInfoArray method which will release the currently held variable and set the pointer to nil which is safe.
     
  7. thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #7
    Ok, that makes sence. So if I have a variable with a property assign that is alloc-ed in the viewdidload I check in the viewdidload if it already excists and if not I alloc it. In the viewDidUnload I set this variable to nil. In the dealloc i release this variable or should I set it to nil there aswell?

    Variables allocated in the init method? Where should I do what with these? The init is only called when the viewcontroller was removed from the memory?

    [/QUOTE]
    So in all cases where I have a property and uses setter/getter like this(self.), I should always set this one to nil in the dealloc method? I have read somewhere that using self. in the dealloc in not good practice...?
     
  8. thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #8
    and here another situation:
    I have a popovercontroller and it is set with property retain in the .h file. In the viewdidload it is assigned like this:
    Code:
    InfoPopoverViewController* info = [[InfoPopoverViewController alloc] init];
    	UIPopoverController* infoPopover = [[UIPopoverController alloc] initWithContentViewController:info];
    	[info release];
    	infoPopover.delegate = self;
    
    	self.infoPopoverController = infoPopover;
    	[infoPopover release];
    
    After this the self.infoPopoverController has retain +1 right? I am not actually allocating this object in the viewDidLoad - should I set it to nil in the viewDidUnload method? Or only release it in the dealloc?

    MACloop
     
  9. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #9
    As to where you should release it: you should release it as soon as you no-longer need it. This could be in any of the methods you mention or potentially earlier.
     
  10. thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #10
    ok, I need it as long as the viewcontroller lives. That would mean I have to release it in the dealloc, right?
    MACloop
     
  11. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #11
    Yes
     
  12. thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #12
    Ok, at least one part is clear ;-)

    I have these situations and I am not sure that I got them all. This is how I would do it:

    1)
    in .h
    IBOutlet NSString *x;
    @property(nonatomic, retain)NSString *x;

    in .m
    self.x = something;

    in viewDidUnload
    self.x = nil;
    dealloc
    [x release];

    2)
    in .h
    NSString *x;
    @property(nonatomic, retain)NSString *x;

    in .m
    self.x = something;

    viewDidUnload
    nothing

    dealloc
    [x release];

    3)
    in .h
    NSString *x;

    in .m
    NSString *x = [[NSString alloc]initWithString:mad:"Something"];

    viewDidUnload
    nothing

    dealloc
    [x release];

    4)
    in .h
    NSMutableArray *x;
    @property (nonatomic, assign)NSMutableArray *x;

    in .m
    in the init-method not in viewDidLoad
    x = [[NSMutableArray alloc]initWithArray:someArray];

    viewDidUnload
    nothing

    dealloc
    [x release];


    Is this the right way to do it?
    MACloop
     
  13. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #13
    Can you sort out some code tags. The above is unreadable.

    Edit, OK I think I've worked out the mess.

    1) Think about what self.x=nil is doing. Think about the synthesized setter. What code is in there? Does it do a release? So should you release again?

    2) Fine

    3) You have shadowed the variable you declared in the .h file in the .m file. This will have unexpected consequences.

    4) I don't see what it matter whether the assignment is in init or viewDidLoad. The same memory management rules apply. In this case it should be fine as you release in dealloc.
     
  14. thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #14
    sorry....

    self.x=nil is releasing and removing the variable... I think this is the point - I do not want a leak but I certanly not want a overretain... so should I only release in dealloc? and do nothiong in viewDidUnload?

    2) Fine

    Ups is was supposed to be
    in .h
    Code:
    NSString *x;
    in .m
    Code:
    x = [[NSString alloc]initWithString:@"Something"];
    viewDidUnload
    nothing

    dealloc
    Code:
    [x release];
    Ok, so you would do nothing in viewDidUnload here?
     
  15. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #15
    As you do not say you are doing alloc/init, just "something" the assumption is that you are calling the setter with an autoreleased variable. The setter will retain it. When you call the setter with nil it will release it. Releasing again in dealloc will be releasing an already fully released object.

    Given that you've been asking questions on here about memory management for, quite literally, months it's time to step back and ask why. The rules are very, very simple. Take some time and learn them and then think about what they mean when you apply them. Take a pencil and some paper and actually work through the lifecycles of the objects.
     
  16. thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #16
    OK, yes I think I have to do that again... it is not that trivial I think 1: because everyone I aske gives me different answers 2: there is no right or wrong - every situation is different... I know what overretain and leaks are and I know that everything I alloc/retain also have to be released sometime later on. What I obviously did get wrong is that both dealloc and viewDidUnload may be called in... and I think the comment in the tempalte from apple is a bit missleading. It says:
    Code:
    // Release any retained subviews of the main view.
    	// e.g. self.myOutlet = nil;
    but it is not so easy :-(
    MACloop
     
  17. thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #17
    So, I read about memory management and about memory warnings once again. Perhaps it is me not being a native english speaker who doea not understand what they are trying to say. I read here and there is noting written about the problematics in using viewDidUnload and dealloc. I also read in the reference for UIView that when the viewDidUnload method is called, the view is nil. That means, as I thought, that everything owned by the view could be set to nil /released. But that is not correct if I understand your former advice correctly? Do I actually have to look in the dealloc if every var is not nil ie:
    Code:
    - (void)viewDidUnload {
        if(self.annotation != nil)
            self.annotation = nil;
        [super viewDidUnload];
    
    }
    
    
    - (void)dealloc {
        if(self.annotation != nil)
            [annotation release];
        [super dealloc];
    }
    
     
  18. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #18
    I don't use any nibs at all in any of my iPhone apps so hopefully someone who does will come along to help you. I find that creating everything in code means I know exactly when objects will be released so I don't worry about this sort of thing.
     
  19. thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #19
    ok, so you are not doing anything in viewDidUnload?

    ..and what do you think? Could this be the way to do it? I try not to use nib files but to rewrite the program now would take a very long time. Do you see any problems with the suggestion I did above? Looking in the dealloc and the viewDidUnload if the variable is not nil....
     
  20. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #20
    I'm at work so I don't have access to my code. I might be if I consider it to be the correct thing to do. There is no answer that will be 100% correct all of the time: whether you release an object in viewDidUnload is entirely decided by the code structure of your application: you have to use your judgement to do the correct thing. That's what programming is all about.

    I don't know and I'm not about to spend time and mental effort reading all the documentation. That's your job!
     
  21. thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #21
    Yes, that is what programming is about, but I sometime think the documentation is hard to understand and as far as I can see only trivial examples on this is mentioned in the documentation. I know that every situation is different and therefore I made some conrete exapmles before inorder to understand some parts and basics...
     
  22. thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #22
    so one last question:

    I have implemented this solution in this specific case:
    The reason why the map object is reretained is the blue-dot problem, to avoid the map being released before the blue-dot is done.

    .h file
    Code:
    IBOutlet MKMapView *map;
    @property(nonatomic,retain) IBOutlet MKMapView *map;
    .m file
    Code:
    - (void)viewDidUnload {
    	if(map != nil){
    		[self.map retain];//+2
    		[self.map performSelector:@selector(autorelease) withObject:nil afterDelay:5.0];//-1 after delay
    		self.map = nil;//-1
    	}
    	[super viewDidUnload];
    }
    Code:
    - (void)dealloc {
    	if(map != nil){
    		[self.map retain];//+2
    		[self.map performSelector:@selector(autorelease) withObject:nil afterDelay:5.0];//-1 after delay
    		[map release];//-1
    	}
        [super dealloc];
    }
     
  23. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #23
    So what's the question. You have stated what you have done: I don't see a question.
     
  24. thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #24
    well, the question is if this is a safe way to do this?
     
  25. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #25
    In all honesty using performSelector:withObject:afterDelay: to call autorelease looks like it almost has to be an error.
     

Share This Page