Objective-C memory management-reference count

Source: Internet
Author: User

OBJ-CThis quality is "improvedC Language", We all know that C language does not have garbage collection (GC) mechanism (Note: Although obj-c2.0 later added GC function, but not on the iPhone, so for iOS platformProgramThis is almost useless), so when writing a program in obj-C, the release of resources must be manually handled by developers, which is relatively time-consuming.

Reference count

This is an old but effective memory management method. Each object (especially the instance of the class) has a retaincount reference count. when an object is created, retaincount is 1. You can manually call retain method to make retaincount + 1. You can also manually call release method causes the retainCount-1, if the retaincount value is reduced to 0 when the release method is called, the system automatically calls the dealloc method (similar to the dispose method in C #). developers can release or clear resources in dealloc.

1. Basic usage

To demonstrate this basic method, first define a class sample

Sample. h

 
//// Sample. h // memorymanage_1 // created by Jimmy. yang on 11-2-19. // copy 2011 _ mycompanyname __. all rights reserved. // # import <Foundation/Foundation. h> @ interface sample: nsobject {}@ end

Class implementation part sample. m

//// Sample. M // memorymanage_1 // created by Jimmy. yang on 11-2-19. // copy 2011 _ mycompanyname __. all rights reserved. // # import "sample. H "@ implementation sample-(ID) Init {If (Self = [Super init]) {nslog (@" the constructor has been called! Current reference count: % d ", [self retaincount]);} return (Self);}-(void) dealloc {nslog (@" The Destructor will be executed ..., current reference count: % d ", [self retaincount]); [Super dealloc] ;}@ end

CodeIt is very simple, except for constructor and destructor, there is no additional processing.

Main program call

# Import <Foundation/Foundation. h> # import "sample. H "int main (INT argc, const char * argv []) {sample * _ sample = [sample new]; // The constructor is called! Current reference count: 1 nslog (@ "_ sample. retaincount = % d ", [_ sample retaincount]); // 1 [_ sample retain]; nslog (@" _ sample. retaincount = % d ", [_ sample retaincount]); // 2 [_ sample retain]; nslog (@" _ sample. retaincount = % d ", [_ sample retaincount]); // 3 [_ sample release]; nslog (@" _ sample. retaincount = % d ", [_ sample retaincount]); // 2 [_ sample release]; nslog (@" _ sample. retaincount = % d ", [_ sample retaincount]); // 1 [_ sample release]; // The Destructor will be executed ..., current reference count: 1 nslog (@ "_ sample. retaincount = % d ", [_ sample retaincount]); // 1, Note: If the retaincount of the object is referenced immediately after the Destructor is executed, 1 is returned, however, no matter whether you attempt to reference any attribute or method of the object, the nslog (@ "_ sample. retaincount = % d ", [_ sample retaincount]); // After the object is released, if you attempt to reference any other method of the object, then an error is reported // [_ sample retain]; // same as above, return 0 ;}

This code mainly verifies whether retaincount is 1 when the object is just created, and whether retaincount and release can change the value of retaincount. When retaincount is reduced to 0, whether the dealloc function is automatically executed

Nil Problems:

1.1If you declare only one sample-type variable (actually a pointer) without instantiating it, the initial value is nil.

1.2After the variable is instantiated, even if the release is removed, dealloc is successfully called, and its retaincount does not return to 0 immediately (it can be called immediatelyOnce and only once[Xxx
Retaincount]), and the pointer variable itself is not automatically classified as the nil value.

1.3After dealloc is called, you must manually assign a value to nil. The value of retaincount is automatically set to 0.

The above conclusions are obtained from actual experiments. See the following code:

 sample * s; nslog (@" S % @, retaincount = % d ", S = nil? @ "Is nil": @ "is not nil", [s retaincount]); // s is nil, retaincount = 0 s = [sample new]; nslog (@ "S % @, retaincount = % d", S = nil? @ "Is nil": @ "is not nil", [s retaincount]); // s is not nil, retaincount = 1 [S release]; nslog (@ "S % @, retaincount = % d", S = nil? @ "Is nil": @ "is not nil", [s retaincount]); // s is not nil, retaincount = 1 // nslog (@ "S % @, retaincount = % d ", S = nil? @ "Is nil": @ "is not nil", [s retaincount]); // error: Program received ed signal: "exc_bad_access ". S = nil; nslog (@ "S % @, retaincount = % d", S = nil? @ "Is nil": @ "is not nil", [s retaincount]); // s is nil, retaincount = 0 

So tens of millionsDo not use if
(X = nil) or if ([x retaincount] = 0) to determine whether the object is destroyedUnless you manually assign a value to nil after each object is destroyed

2. Complexity

The preceding example is too concise. Only one class can be used independently. If there are multiple classes and there is a link between them, the situation should be more complicated. Next we will design two shoe and man ("Shoes" and "people") categories. Everyone must wear shoes, so the relationship between man and shoe should beMan owns shoe.

Shoe. H Interface Definition

 
# Import <Foundation/Foundation. h> @ interface shoe: nsobject {nsstring * _ shoecolor; int _ shoesize;} // shoe size-(void) setsize :( INT) size;-(INT) size; // shoes color-(void) setcolor :( nsstring *) color;-(nsstring *) color; // set the shoes color and size-(void) setcolorandsize :( nsstring *) pcolor shoesize :( INT) psize; @ end

Shoe. m implementation

//// Shoe. M // memorymanage_1 // created by Jimmy. yang on 11-2-19. // copy 2011 _ mycompanyname __. all rights reserved. // # import "shoe. H "@ implementation shoe // constructor-(ID) Init {If (Self = [Super init]) {_ shoecolor = @" black "; _ shoesize = 35 ;} nslog! ", _ Shoecolor, _ shoesize); Return (Self);}-(void) setcolor :( nsstring *) newcolor {_ shoecolor = newcolor;}-(nsstring *) color {return _ shoecolor;}-(void) setsize :( INT) newsize {_ shoesize = newsize;}-(INT) size {return _ shoesize;}-(void) setcolorandsize :( nsstring *) color shoesize :( INT) size {[self setcolor: Color]; [self setsize: Size] ;}// destructor-(void) dealloc {nslog (@ "% @ % d code shoes are being destroyed! ", _ Shoecolor, _ shoesize); [Super dealloc] ;}@ end

Man. h Definition

/// Man. h // memorymanage_1 // created by Jimmy. yang on 11-2-20. // copy 2011 _ mycompanyname __. all rights reserved. // # import <Foundation/Foundation. h> # import "shoe. H "@ interface man: nsobject {nsstring * _ name; shoe * _ shoe;}-(void) setname :( nsstring *) Name;-(nsstring *) Name; -(void) wearshoe :( shoe *) shoe; @ end

Man. m implementation

/// Man. M // memorymanage_1 // created by Jimmy. yang on 11-2-20. // copy 2011 _ mycompanyname __. all rights reserved. // # import "man. H "@ implementation man // constructor-(ID) Init {If (Self = [Super init]) {_ name = @" No Name ";} nslog (@ "Newcomer \" % @ \ "born! ", _ Name); Return (Self);}-(void) setname :( nsstring *) newname {_ name = newname;}-(nsstring *) name {return _ name;}-(void) wearshoe :( shoe *) shoe {_ shoe = shoe;} // destructor-(void) dealloc {nslog (@ "\" % @ \ "is dying! ", _ Name); [Super dealloc] ;}@ end

Main function call

# Import <Foundation/Foundation. h> # import "shoe. H "# import" man. H "int main (INT argc, const char * argv []) {MAN * Jimmy = [Man new]; [Jimmy setname: @" Jimmy "]; shoe * black40 = [shoe new]; [black40 setcolorandsize: @ "black" shoesize: 40]; [Jimmy wearshoe: black40]; [Jimmy release]; [black40 release]; return 0 ;}

13:05:50. 550 memorymanage [253: a0f] newcomer "No Name" was born!
13:05:50. 560 memorymanage [253: a0f] a pair of 35-yard black shoes!
13:05:50. 634 memorymanage [253: a0f] "Jimmy" is dying!
13:05:50. 636 memorymanage [253: a0f] The Black yard shoes are being destroyed!

The above is the output result. Everything is normal. The resources occupied by Jimmy and black40 are finally released. But it is not reasonable. Since the shoes (black40) belong to Jimmy, why is the person dead (I .e. [Jimmy release])? but still need the main function to burn his shoes? (That is, the main function still writes a line of [black40 release] separately.) when it seems like a person is dead, all the items on the self will be taken together. This is more convenient.

OK. Let's change the dealloc () method in man. m to the following:

 
// Destructor-(void) dealloc {nslog (@ "\" %! ", _ Name); [_ shoe release]; // release _ shoe [Super dealloc] here;}

That is, when man is destroyed, _ shoe is first destroyed. In this way, in the main () function, you no longer need to write a single [black40 release] line to release black40.

Now there is a new situation: Jimmy made a good friend Mike, who became an iron buddy. Then Jimmy decided to share his shoes black40 with Mike, so the main function became like the following:

 
Int main (INT argc, const char * argv []) {MAN * Jimmy = [Man new]; [Jimmy setname: @ "Jimmy"]; shoe * black40 = [shoe new]; [black40 setcolorandsize: @ "black" shoesize: 40]; [Jimmy wearshoe: black40]; man * Mike = [Man new]; [Mike setname: @ "Mike"]; [Mike wearshoe: black40]; // Mike and Jimmy now share a pair of 40-yard-black shoes [Jimmy release]; [Mike release]; return 0 ;}

Trouble: when Jimmy crashes (that is, the [Jimmy release] Line ), he had already destroyed his shoes (maybe he forgot that Mike was wearing it). Then, when Mike died, he was prepared to burn his shoes, black40, the object does not exist. The program runs an error:

Running...
13:38:53. 169 memorymanage [374: a0f] newcomer "No Name" was born!
13:38:53. 176 memorymanage [374: a0f] a pair of 35-yard black shoes!
13:38:53. 177 memorymanage [374: a0f] newcomer "No Name" was born!
13:38:53. 179 memorymanage [374: a0f] "Jimmy" is dying!
13:38:53. 181 memorymanage [374: a0f] The Black yard shoes are being destroyed!
13:38:53. 183 memorymanage [374: a0f] "Mike" is dying!
Program
Received Signal: "exc_bad_access ".
Sharedlibrary apply-load-rules all
(GDB)

The red part indicates that the program has an error: bad_access indicates that the access address does not exist.

The best solution is to return to the origin again, man. m's dealloc does not jointly release the shoe instance, and then put the shared shoe in the main function. After all the people are suspended, the shoe instance will be destroyed. However, it is estimated that the main () the function has an opinion: You two are dead, and you need to take care of it later.

This example is nothing more thanPrinciples: For new objects, the corresponding release must be used to offset the impact caused by using retain, and vice versa. Otherwise, the object will not be destroyed, or early destruction leads to invalid references and errors.

Next, let's take a look at how to useAuto Release poolTo handle the reference count in another way.

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.