Analysis of Memory Management-setter Method

Posted by Loryman on Mon, 08 Jul 2019 22:36:45 +0200

In the last article, we analyzed the memory management of two related objects. Based on the previous article, we continue to further analyze the memory management of multi-objects and the parsing of setter method.

  • First create two classes, Person
Person.h file
#import "Car.h"
@interface Person : NSObject
{
    Car *_car;
}

-(void)setCar:(Car *)car;
-(Car *)car;
@end
Person.m file

#import "Person.h"

@implementation Person

-(void)setCar:(Car *)car{

    _car = [car retain];
}


-(Car *)car{
    return _car;
}
-(void)dealloc{

    [_car release];
    [super dealloc];
    NSLog(@"---person Released-");
}
@end
  • Class Car
Car.h file
#import <Foundation/Foundation.h>

@interface Car : NSObject
{
    int _speed;
}

-(void)setSpeed:(int)speed;
-(int)speed;
@end
Car.m file

#import "Car.h"

@implementation Car
-(void)setSpeed:(int)speed{

    _speed = speed;
}
-(int)speed{

    return _speed;
}
-(void)dealloc{

    NSLog(@"The velocity is zero.--%d Of car Released",_speed);
    [super dealloc];

}
@end
  • Related operations in Controller
- (void)viewDidLoad {
    [super viewDidLoad];

    //p - 1
    Person *p = [[Person alloc]init];
    //car - 1
    Car *car = [[Car alloc]init];
    car.speed = 100;

    //car - 2
    [p setCar:car];

    //car - 1
    [car release];
    car = nil;

    //p - 0 && car = 0
    [p release];
    p = nil;

  }

It's printed from the code above.

2017-04-16 18:28:02.537 Memory Management-Application Count 1 [19267:395083] Speed is - 100 car released
 2017-04-16 18:28:02.538 Memory Management-Application Count 1 [19267:395083]-person released-

No problem!

but, we have to change cars one day when we get rich. Okay, let's change new cars and see if there's anything wrong.

- (void)viewDidLoad {
    [super viewDidLoad];

    //p - 1
    Person *p = [[Person alloc]init];
    //car - 1
    Car *car = [[Car alloc]init];
    car.speed = 100;

    //car - 2
    [p setCar:car];

    //car1 - 1
    Car *car1 = [[Car alloc]init];
    car1.speed = 200;

    //Car 1 - 2 changed
    [p setCar:car1];
    //car - 1
    [car release];
    car = nil;

    //car1 - 1
    [car1 release];
    car1 = nil;

    //p - 0 && car1 = 0
    [p release];
    p = nil;

}

You can see that compared with the above code, we created a new car, namely "car1". At this point, we print and find out.

2017-04-16 18:58:48.624 Memory Management-Application Count 1 [20200:419639] Speed is - 200 car released
 2017-04-16 18:58:48.626 Memory Management-Application Count 1 [20200:419639]-person released-

Well, we don't have three objects right now. It's reasonable that all three should be released. Simply, let's analyze the code.

    [p setCar:car];

There's a problem with car being an old car. At this point, the reference count of car is already 2, and then we change cars until

[car release];

In this step, car's reference count is - 1, and retainCount is 1. So it won't be released. So, we are

-(void)setCar:(Car *)car{

    _car = [car retain];
}

This step should do something, we changed the car, do not want this old car, we should have the responsibility to cancel it, so before holding a new car, first release the old car.

-(void)setCar:(Car *)car{

    [_car release];
    _car = [car retain];
}

At this point, let's see the results.

2017-04-16 19:08:35.685 Memory Management-Application Count 1 [20617:429974] Speed - 100 car Released
 2017-04-16 19:08:35.686 Memory Management-Application Count 1 [20617:429974] Speed is - 200 car released
 2017-04-16 19:08:35.686 Memory Management-Application Count 1 [20617:429974]-person released-

Soga, the result we want appears. But is that perfect? Continue

- (void)viewDidLoad {
    [super viewDidLoad];

    //p - 1
    Person *p = [[Person alloc]init];
    //car - 1
    Car *car = [[Car alloc]init];
    car.speed = 100;

    //car - 2
    [p setCar:car];


    //car - 1
    [car release];
    [p setCar:car];

    car = nil;


    //p - 0 && car1 = 0
    [p release];
    p = nil;

}

As shown above, we accidentally assign p again after [car release]. At this point, after running the code

2017-04-16 20:27:35.446 memory management-Application Count 1[22629:480814] The velocity is zero.--100 Of car Released
2017-04-16 20:27:35.446 memory management-Application Count 1[22629:480814] *** -[Car retain]: message sent to deallocated instance 0x60800001f010
(lldb)

Wrong report. why?
We analyze the code

    //car - 2
    [p setCar:car];

    //car - 1
    [car release];

The p here will arrive when it has a new car

-(void)setCar:(Car *)car{

    [_car release];
    _car = [car retain];
}

Here _car is the current car, first released, then his reference count is 1, then [car release] and then the reference counter is 0. Let's go on to

    [p setCar:car];

The car here is still the previous _car, and the previous car reference count is zero. When we send retain messages, we become zombie objects, so we make a mistake.

  • What about the solution?

If the incoming car is the same as the current car, there is no need to perform the operation inside, then we can judge.

-(void)setCar:(Car *)car{

    if (_car != car) {

        [_car release];
        _car = [car retain];
    }

}

If that's the case, the result is

2017-04-16 20:40:23.719 Memory Management-Application Count 1 [23174:495402] Speed is - 100 car released
 2017-04-16 20:40:23.720 Memory Management-Application Count 1 [23174:495402]-person released-

ok. This solves the problems that may arise.