Objective c, Memory management of instance members

后端 未结 6 695
南方客
南方客 2020-12-02 00:58

I am confuzed by the memory management of instance members. I have a class with a ivar:

DetailedResultsTableViewController *detailedResultsTableViewControlle         


        
相关标签:
6条回答
  • 2020-12-02 01:28

    Your @interface is correct, but your implementation slightly wrong:

    @implmentation MyClass
    
    //It's good practice to explicitly state the a variable name for this property to use 
    //The common approach is to use the property name with a leading underscore
    //This prevents accidentally accessing the ivar within the class instead of using the     accessor methods. You should only access the ivar directly within the accessor methods (which in these case are being created for you by  @synthesize), in the designate init method and dealloc
    @synthesize detailedResultsTableViewController = _detailedResultsTableViewController;
    
    -(void)dealloc
    {
    //...
        [_detailedResultsTableViewController release];
    //...
    }
    
    @end
    

    When accessing the property:

    myClass.detailedResultsMapViewController = [[[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil] autorelease];   
    

    The code that is setting the method does not 'own' the new value therefore it must autorelease.

    0 讨论(0)
  • 2020-12-02 01:32

    First you should not look at the retaincount, it not really reliable.

    Second your property is set to retain. So when you assign some thing to it, it will increase the reatincount. As will alloc.

    Doing it like this you are leaking:

    self.detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil];
    

    you should do:

    DetailedResultsMapViewController *vc = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil];
    self.detailedResultsMapViewController =vc;
    [vc release], vc= nil;
    

    Or use Autorelease:

    self.detailedResultsMapViewController = [[[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil] autorelease];
    
    0 讨论(0)
  • 2020-12-02 01:33

    When you have a retained property it increments the retain count on any self.myProperty =

    Alloc also increments the retain count. So in your case the retain count is 2.

    There a couple approaches.

    1. You could include an autorelease in your init alloc statement
    2. Create a temporary variable while you set up your instance then when you are done set your property to it and release the temp.
    3. Drop the self. for this assignment. The catch here is if you have a custom setMyVariable: function then it will not get called without the self.
    4. Use ARC and you don't have to worry about any of this.
    0 讨论(0)
  • 2020-12-02 01:38

    You're doing two things wrong.

    Firstly:

    self.detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil];
    

    should be:

    self.detailedResultsMapViewController = [[[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil] autorelease];
    

    because you are using self.… you are using the memory management semantic of the property, which in this case is retain so it is retained again.

    Secondly:

    You've used retainCount. Which has no use whatsoever in debugging memory management.

    If you want to know why this is wrong look at the other answers regarding retainCount right here on Stack Overflow, or read @bbum's fuller description of why you shouldn't use it.

    You broke the memory management rules by not releasing something you owned. This alone is enough to find the problem in your code. In fact, I'm surprised that the static analyser didn't pick up this problem.

    0 讨论(0)
  • 2020-12-02 01:51

    Using the property and synthesize gives you a new method. In this instance, you would have a new set and get method for the detailedResultsTableViewController. This is generated for you when you compile (ie there is no code that you have to add)

    This set method will be

    - (void)setDetailedResultsTableViewController:(DetailedResultsTableViewController *)c 
    {
        if (detailedResultsTableViewController != nil) 
        {
            [detailedResultsTableViewController release];
            detailedResultsTableViewController = nil;
        }
        detailedResultsTableViewController = [c retain];
    }
    

    So, when you call

    self.detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] init...];
    

    What you are actually calling is

    [self setDetailedResultsMapViewController:[[DetailedResultsMapViewControler...]]];
    

    And so you are actually doing two retains. One where you are calling alloc...init. and then the other because you are implicitly calling the setDetailedResultsMapViewController which will then do a retain as well.

    If you are using properties, you would use

    DetailedResultsTableViewController *d = [[DetailedResultsMapViewController alloc] init...]
    self.detailedResultsMapViewController = d;
    [d release];
    

    The benefit of this is that you don't have to remember to release the old object before assigning the new as the synthesized method does that for you. You can also just do

    self.detailedResultsMapViewController = nil;
    

    in your dealloc method and you won't have to worry if you have already released it elsewhere.

    This is useful to know because you can override the set method by manually entering the code which allows you to do things when the objects are set.

    0 讨论(0)
  • 2020-12-02 01:51

    Whenever you declare a property as retain, and you refer to it using self.myiVar it will use the setter, and the setter will retain the object. Additionally because you are using alloc on the object, that will also increase the retain count to 2, bringing the retain count to 2.

    As a note I would not trust the retainCount too much, it gives incorrect results sometimes, however it is correct this time.

    Here are some options to avoid it having a retain count of 2:

    //Refer to it with using the setter
    detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil];
    
    //Autorelease it after alloc
    detailedResultsMapViewController = [[[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil] autorelease];
    
    0 讨论(0)
提交回复
热议问题