Objective-C memory management-instance analysis

Source: Internet
Author: User

Note: This is an example of "objective-C basic tutorial". However, the original book is limited to space and has a simple analysis. It is difficult to read it for the first time. Here we will discuss it in detail.

Scenario: There are two types of car and engine: "car" and "engine ".

First, let's look at the initial version:

Engine. h

 
# Import <Cocoa/cocoa. h> @ Interface Engine: nsobject @ property int flag; @ end // Engine

Engine. m

 
# Import "engine. H "@ implementation engine @ synthesize flag;-(nsstring *) Description {return ([nsstring stringwithformat: @" I am engine % d, my retaincount = % d ", flag, [self retaincount]);} // description-(void) dealloc {nslog (@ "this engine % d is going to die. ", flag); [Super dealloc]; nslog (@" this engine % d is dead. ", flag);} @ end // Engine

CodeNot complex. The engine class has a flag attribute, which is used to identify the secondary output time zone by the current engine. The description method (equivalent to the tostring () method of the object in C #) is used to return a string that describes itself. The last step is the dealloc method, which is used to clear resources used by the user.

Car. h

 
# Import <Cocoa/cocoa. h> # import "engine. H "@ interface car: nsobject {Engine * engine;} @ property int flag;-(void) setengine: (engine *) newengine;-(Engine *) engine; @ end // car

Car. m

 
# Import "car. H "# import" engine. H "@ implementation car @ synthesize flag;-(ID) Init {If (Self = [Super init]) {Engine = [engine new]; // when each car was born, an empty engine (with a flag = 0) is preset, and this object needs to be released eventually! } Return (Self);} // init-(Engine *) engine {return (ENGINE) ;}// engine-(void) setengine: (engine *) newengine {Engine = newengine;} // setengine-(void) dealloc {nslog (@ "The car % d is going to die. ", flag); nslog (@" % @ ", engine); [engine release]; // release affiliated resources: Engine [Super dealloc]; nslog (@ "The car % d is dead. ", flag);} @ end // car

Explanation: In the init method, a default engine (with the flag value 0) is preset for each car at the time of delivery, and the setengine method is used to set a new engine for the car, in dealloc, the release engine is attached when the car is destroyed.

First considerFirst case:

A car is installed with a new engine, which is destroyed after use, but the engine can be used for other purposes (such as for other cars ), the new engine is used up and destroyed!

 
Car * car1 = [Car new]; car1.flag = 1; engine * engine1 = [engine new]; engine1.flag = 1; [car1 setengine: engine1]; [car1 release]; nslog (@ "% @", engine1); // here the simulation engine is used for other purposes [engine1 release];

The above code has at least two problems:

1.1In the constructor init, the preset default engine (that is, the flag = 0 engine) is not released.

1.2The car has released the engine in the dealloc method. Therefore, after the car is released, the engine will disappear and there is no way to use it for other purposes. Therefore, lines 7 and 8 cannot be run, and an error is reported! This is more serious than memory leakage.

First, let's solve the most serious 2nd problems. At least let it run. The root cause is that the engine is also released to release when the car is destroyed! There are two ways to solve it:

1. Remove [engine release] from car. M class dealloc, but this irresponsible approach is not recommended based on the principle of "self-managed children.

2. In the setengine method, manually call the [newengine retain] method to add 1 to the reference count of the engine, which can offset the car. the impact of [engine release] in the M-Class dealloc method (one plus one minus, exactly offset !).

The setengine method in car. M has the second version:

 
-(Void) setengine: (engine *) newengine {Engine = [newengine retain];} // setengine

Re-compile, finally passed, and can run. Leave question 1.1 aside before considering it.Case 2:

Another car was installed with the new engine engine1. After trying it, I felt uncomfortable. So I lost engine1 and changed it to another engine engine2 !)

 
Car * car1 = [Car new]; car1.flag = 1; engine * engine1 = [engine new]; engine1.flag = 1; [car1 setengine: engine1]; // new engine engine1 [engine1 release]; // if it is uncomfortable, engine * engine2 = [engine new]; engine2.flag = 2; [car1 setengine: engine2] is thrown. // change the new engine engine2 [car1 release]; // car1 decommission [engine2 release] after use; // The new engine engine2 is no longer needed.

There are two problems:

2.1Engine1 was first added, and then retain again in setengine, that is to say, its retaincount is 2. Although the code is release once, it can only reduce retaincount to 1, it cannot be destroyed!

2.2The problem mentioned in section 1.1 still exists, that is, the default engine engine0 preset by car in the init method has been ignored and is not freed.

Maybe, you and I have all thought of it. In the setengine method, you can first kill the old engine and then mount the new engine. This is OK! Okay, the third version of setengine appears:

 
-(Void) setengine: (engine *) newengine {[engine release]; engine = [newengine retain];} // setengine

It seems that everyone is happy, but things are not finished yet, and there are new situations:Case 3

Two cars, car1 and car2, and car1, changed the new engine engine1, and then ran to play with car2. car2 thought the new engine was good, so it was required to share the new engine engine1 with car1, but the problem was: before car2 was started, engine1 was abandoned by someone (maybe car1 himself or the main () function of the car owner!

Engine * engine1 = [engine new]; // engine1.retaincount = 1engine1. flag = 1; car * car1 = [Car new]; car1.flag = 1; car * car2 = [Car new]; car2.flag = 2; [car1 setengine: engine1]; // car1 changed the new engine engine1 [engine1 release]; // then soon it was discarded again [car2 setengine: [car1 engine]; // car2 and car1 need to share engine1 // Finally, car1 and car2 are thrown by the main function of the car owner [car2 release]; [car1 release];

Problem: in the case of 16 rows of [car2 release], car2 has completely destroyed engine1 (maybe car2 has forgotten that engine1 is the property it shares with car1 ), then, when [car1 release], when the dealloc method of car1 was in [engine release], it was accidentally found that engine1 was no longer in the world and eventually it was angry.ProgramSo we went on strike!

Last setengine version

 
-(Void) setengine: (engine *) newengine {[newengine retain]; [engine release]; engine = newengine;} // setengine

In fact, it is to split the second line of code of the previous version into three lines, which turns to retain first and then release. It seems to have the same meaning, but after careful analysis, you will find that if the engine and newengine areSame objectWhen the two pointers point to the same memory, and the retaincount of newengine (actually the engine) is 1, the original version will cause newengine (in fact, the engine) to be destroyed. After such processing, it will be retained.

Finally, verify whether a final version can cope with the three situations mentioned above:

Result of the first case:

09:17:52. 951 carparts [257: a0f] This engine 0 is going to die.
09:17:52. 957 carparts [257: a0f]This engine 0 is dead.
09:17:52. 959 carparts [257: a0f] The Car 1 is going to die.
09:17:52. 961 carparts [257: a0f] I am Engine 1, my retaincount = 2
09:17:52. 962 carparts [257: a0f]The car 1 is dead.
09:17:52. 966 carparts [257: a0f] I am Engine 1, my retaincount = 1
09:17:52. 968 carparts [257: a0f] This Engine 1 is going to die.
09:17:52. 969 carparts [257: a0f]This engine 1 is dead.

Result of the second case:

09:19:30. 639 carparts [291: a0f] This engine 0 is going to die.
09:19:30. 644 carparts [291: a0f]This engine 0 is dead.
09:19:30. 646 carparts [291: a0f] This Engine 1 is going to die.
09:19:30. 648 carparts [291: a0f]This engine 1 is dead.
09:19:30. 650 carparts [291: a0f] The Car 1 is going to die.
09:19:30. 652 carparts [291: a0f] I am Engine 2, my retaincount = 2
09:19:30. 653 carparts [291: a0f]The car 1 is dead.
09:19:30. 655 carparts [291: a0f] This engine 2 is going to die.
09:19:30. 657 carparts [291: a0f]This engine 2 is dead.

Result of the third case:

09:21:02. 549 carparts [324: a0f] This engine 0 is going to die.
09:21:02. 554 carparts [324: a0f]This engine 0 is dead.
09:21:02. 556 carparts [324: a0f] This engine 0 is going to die.
09:21:02. 558 carparts [324: a0f]This engine 0 is dead.
09:21:02. 559 carparts [324: a0f] The Car 2 is going to die.
09:21:02. 561 carparts [324: a0f] I am Engine 1, my retaincount = 2
09:21:02. 563 carparts [324: a0f]The car 2 is dead.
09:21:02. 571 carparts [324: a0f] The Car 1 is going to die.
09:21:02. 573 carparts [324: a0f] I am Engine 1, my retaincount = 1
09:21:02. 575 carparts [324: a0f] This Engine 1 is going to die.
09:21:02. 578 carparts [324: a0f]This engine 1 is dead.
09:21:02. 587 carparts [324: a0f]The car 1 is dead.

From the output result, no matter which case, the car and engine resources are finally released!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.