Objective-C memory management in IOS development (40)-Reference count

Source: Internet
Author: User

Obj-CThis quality is "Improved C Language", we all know that C language is no garbage collection (GC) mechanism (Note: Although obj-c2.0 later added GC function, but it cannot be used on the iphone, so this is almost useless for iOS platform programmers), 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 reference count of retainCount. When the object is created, retainCount is 1. You can manually call the retain method to make retainCount + 1, you can also manually call the release method to make the retainCount-1, when calling the release method, if the retainCount value is reduced to 0, the system will automatically call the dealloc method of the object (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 (@ "constructor called! Current reference count: % d ", [self retainCount]);
}
Return (self );
}

-(Void) dealloc {
NSLog (@ "destructor to be executed..., current reference count: % d", [self retainCount]);
[Super dealloc];
}
@ End
The code 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]; // destructor to 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 property or method of the object, an error will be reported.
NSLog (@ "_ sample. retainCount = % d", [_ sample retainCount]); // if you attempt to reference any other method of the object after the object is released, an error is returned.
// [_ Sample retain]; // same as above, an error will be reported
 
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.1 if only one Sample type variable (actually a pointer) is declared without instantiation, the initial value is nil.

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

1.3 after dealloc is called, you must manually assign a value to nil and retainCount will be automatically returned 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
Therefore, do not use if (x = nil) or if ([x retainCount] = 0) to determine whether the object is destroyed, unless you destroy the object each time, manually explicitly assign the value to nil

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. Therefore, the relationship between Man and Shoe should be Man's Shoe.

Shoe. h Interface Definition

# Import <Foundation/Foundation. h>


@ Interface Shoe: NSObject {
NSString * _ shoeColor;
Int _ shoeSize;
}

// Shoe size
-(Void) setSize :( int) size;
-(Int) Size;

// Shoe color
-(Void) setColor :( NSString *) color;
-(NSString *) Color;

// Set the shoe 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 (@ "\" % @ \ "is dying! ", _ Name );
[_ Shoe release]; // release _ shoe here
[Super dealloc];
}
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 40-yard-black pair of 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 than a Principle: For new objects, the impact caused by using retain must be offset by the corresponding release, and vice versa. Otherwise, either the object will not be destroyed, or the early destruction will lead to invalid references and errors.

 

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.