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.