• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

ObjC(Objective-C)的内存管理之-引用计数

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

obj-c本质就是"改进过的c语言",大家都知道c语言是没有垃圾回收(GC)机制的(注:虽然obj-c2.0后来增加了GC功能,但是在 iphone上不能用,因此对于iOS平台的程序员来讲,这个几乎没啥用),所以在obj-c中写程序时,对于资源的释放得由开发人员手动处理,相对要费 心一些。

引用计数

这是一种古老但有效的内存管理方式。每个对象(特指:类的实例)内部都有一个retainCount的引用计数,对象刚被创建时,retainCount为1,可以手动调用retain方法使retainCount+1,同样也可以手动调用release方法使retainCount-1,调用release方法时,如果retainCount值减到0,系统将自动调用对象的dealloc方法(类似于c#中的dispose方法),开发人员可以在dealloc中释放或清理资源。

1、基本用法

为了演示这种基本方式,先定义一个类Sample

类接口部分Sample.h

1 //
2 // Sample.h
3 // MemoryManage_1
4 //
5 // Created by jimmy.yang on 11-2-19.
6 // Copyright 2011 __MyCompanyName__. All rights reserved.
7 //
8
9 #import <Foundation/Foundation.h>
10
11 @interface Sample : NSObject {
12
13 }
14 @end

类实现部分Sample.m

1//
2// Sample.m
3// MemoryManage_1
4//
5// Created by jimmy.yang on 11-2-19.
6// Copyright 2011 __MyCompanyName__. All rights reserved.
7//
8
9#import "Sample.h"
10
11@implementation Sample
12
13-(id) init
14{
15 if (self=[super init]){
16 NSLog(@"构造函数被调用了!当前引用计数:%d",[self retainCount]);
17 }
18 return (self);
19}
20
21-(void) dealloc{
22 NSLog(@"析构函数将要执行...,当前引用计数:%d",[self retainCount]);
23 [super dealloc];
24}
25@end

代码很简单,除了"构造函数"跟"析构函数"之外,没有任何其它多余处理。

主程序调用

1#import <Foundation/Foundation.h>
2#import "Sample.h"
3
4int main (int argc, const char * argv[]) {
5
6 Sample *_sample = [Sample new]; //构造函数被调用了!当前引用计数:1
7 NSLog(@"_sample.retainCount=%d",[_sample retainCount]);//1
8
9 [_sample retain];
10 NSLog(@"_sample.retainCount=%d",[_sample retainCount]);//2
11
12 [_sample retain];
13 NSLog(@"_sample.retainCount=%d",[_sample retainCount]);//3
14
15 [_sample release];
16 NSLog(@"_sample.retainCount=%d",[_sample retainCount]);//2
17
18 [_sample release];
19 NSLog(@"_sample.retainCount=%d",[_sample retainCount]);//1
20
21 [_sample release];//析构函数将要执行...,当前引用计数:1
22 NSLog(@"_sample.retainCount=%d",[_sample retainCount]);//1,注:即便是在析构函数执行后,如果立即再次引用对象的retainCount,仍然返回1,但以后不管再试图引用该对象的任何属性或方法,都将报错
23 NSLog(@"_sample.retainCount=%d",[_sample retainCount]);//对象被释放之后,如果再尝试引用该对象的任何其它方法,则报错
24 //[_sample retain];//同上,会报错
25
26 return 0;
27}

这段代码主要验证:对象刚创建时retainCount是否为1,以及retain和release是否可以改变retainCount的值,同时retainCount减到0时,是否会自动执行dealloc函数

nil 的问题:

1.1 如果仅声明一个Sample类型的变量(其实就是一个指针),而不实例化,其初始值为nil

1.2 变量实例化以后,就算release掉,dealloc被成功调用,其retainCount并不马上回到0(还能立即调用一次且仅一次[xxx retainCount]),而且指针变量本身也不会自动归为nil值

1.3 dealloc被调用后,必须手动赋值nil,retainCount才会自动归0

以上结论是实际试验得出来的,见下面的代码:

1Sample *s ;
2NSLog(@"s %@,retainCount=%d",s==nil?@"is nil":@"is not nil",[s retainCount]);//s is nil,retainCount=0
3s = [Sample new];
4NSLog(@"s %@,retainCount=%d",s==nil?@"is nil":@"is not nil",[s retainCount]);//s is not nil,retainCount=1
5[s release];
6NSLog(@"s %@,retainCount=%d",s==nil?@"is nil":@"is not nil",[s retainCount]);//s is not nil,retainCount=1
7//NSLog(@"s %@,retainCount=%d",s==nil?@"is nil":@"is not nil",[s retainCount]);//报错:Program received signal: “EXC_BAD_ACCESS”.
8s = nil;
9NSLog(@"s %@,retainCount=%d",s==nil?@"is nil":@"is not nil",[s retainCount]);//s is nil,retainCount=0

所以千万别用if (x == nil) 或 if ([x retainCount]==0)来判断对象是否被销毁,除非你每次销毁对象后,手动显式将其赋值为nil

2、复杂情况

上面的示例过于简章,只有一个类自己独耍,如果有多个类,且相互之间有联系时,情况要复杂一些。下面我们设计二个类Shoe和Man(即“鞋子类”和”人“),每个人都要穿鞋,所以Man与Shoe之间应该是Man拥有Shoe的关系。

Shoe.h接口定义部分

1 #import <Foundation/Foundation.h>
2
3
4 @interface Shoe : NSObject {
5 NSString* _shoeColor;
6 int _shoeSize;
7 }
8
9 //鞋子尺寸
10 -(void) setSize:(int) size;
11 -(int) Size;
12
13 //鞋子颜色
14 -(void) setColor:(NSString*) color;
15 -(NSString*) Color;
16
17 //设置鞋子的颜色和尺码
18 -(void) setColorAndSize:(NSString*) pColor shoeSize:(int) pSize;
19
20 @end

Shoe.m实现部分

1 //
2 // Shoe.m
3 // MemoryManage_1
4 //
5 // Created by jimmy.yang on 11-2-19.
6 // Copyright 2011 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "Shoe.h"
10
11
12 @implementation Shoe
13
14 //构造函数
15 -(id)init
16 {
17 if (self=[super init]){
18 _shoeColor = @"black";
19 _shoeSize = 35;
20 }
21 NSLog(@"一双 %@ %d码 的鞋子造好了!",_shoeColor,_shoeSize);
22 return (self);
23 }
24
25 -(void) setColor:(NSString *) newColor
26 {
27 _shoeColor = newColor;
28 }
29
30 -(NSString*) Color
31 {
32 return _shoeColor;
33 }
34
35 -(void) setSize:(int) newSize
36 {
37 _shoeSize = newSize;
38 }
39
40 -(int) Size
41 {
42 return _shoeSize;
43 }
44
45 -(void) setColorAndSize:(NSString *)color shoeSize:(int)size
46 {
47 [self setColor:color];
48 [self setSize:size];
49 }
50
51
52 //析构函数
53 -(void) dealloc
54 {
55 NSLog(@"%@ %d码的鞋子正在被人道毁灭!",_shoeColor,_shoeSize);
56 [super dealloc];
57 }
58
59
60 @end

Man.h定义部分

1 //
2 // Man.h
3 // MemoryManage_1
4 //
5 // Created by jimmy.yang on 11-2-20.
6 // Copyright 2011 __MyCompanyName__. All rights reserved.
7 //
8
9 #import <Foundation/Foundation.h>
10 #import "Shoe.h"
11
12
13 @interface Man : NSObject {
14 NSString *_name;
15 Shoe *_shoe;
16 }
17
18
19 -(void) setName:(NSString*) name;
20 -(NSString*)Name;
21
22 -(void) wearShoe:(Shoe*) shoe;
23 @end

Man.m实现部分

1 //
2 // Man.m
3 // MemoryManage_1
4 //
5 // Created by jimmy.yang on 11-2-20.
6 // Copyright 2011 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "Man.h"
10
11
12 @implementation Man
13
14 //构造函数
15 -(id)init
16 {
17 if (self=[super init]){
18 _name = @"no name";
19 }
20 NSLog(@"新人\"%@\"出生了!",_name);
21 return (self);
22 }
23
24
25 -(void) setName:(NSString *)newName
26 {
27 _name =newName;
28 }
29
30 -(NSString*)Name
31 {
32 return _name;
33 }
34
35 -(void) wearShoe:(Shoe *)shoe
36 {
37 _shoe = shoe;
38 }
39
40 //析构函数
41 -(void) dealloc
42 {
43 NSLog(@"\"%@\"要死了! ",_name);
44 [super dealloc];
45 }
46
47 @end

main函数调用

1#import <Foundation/Foundation.h>
2#import "Shoe.h"
3#import "Man.h"
4
5int main (int argc, const char * argv[]) {
6
7 Man *jimmy = [Man new];
8 [jimmy setName:@"Jimmy"];
9
10
11 Shoe *black40 =[Shoe new];
12 [black40 setColorAndSize:@"Black" shoeSize:40];
13
14 [jimmy wearShoe:black40];
15
16 [jimmy release];
17 [black40 release];
18
19 return 0;
20
21}

2011-02-23 13:05:50.550 MemoryManage[253:a0f] 新人"no name"出生了!
2011-02-23 13:05:50.560 MemoryManage[253:a0f] 一双 black 35码 的鞋子造好了!
2011-02-23 13:05:50.634 MemoryManage[253:a0f] "Jimmy"要死了!
2011-02-23 13:05:50.636 MemoryManage[253:a0f] Black 40码的鞋子正在被人道毁灭!

以上是输出结果,一切正常,jimmy与black40占用的资源最终都得到了释放。但是有一点不太合理,既然鞋子(black40)是属于人 (jimmy)的,为什么人死了(即:[jimmy release]),却还要main函数来责任烧掉他的鞋子?(即:main函数中还是单独写一行[black40 release]) 貌似人死的时候,就连带自上的所有东西一并带走,这样更方便吧。

ok,我们来改造一下Man.m中的dealloc()方法,改成下面这样:

1//析构函数
2-(void) dealloc
3{
4 NSLog(@"\"%@\"要死了! ",_name);
5 [_shoe release];//这里释放_shoe
6 [super dealloc];
7}

即:在Man被销毁的时候,先把_shoe给销毁。这样在main()函数中,就不再需要单独写一行[black40 release]来释放black40了.

现在又有新情况了:jimmy交了一个好朋友mike,二人成了铁哥们,然后jimmy决定把自己的鞋子black40,跟mike共同拥有,于是main函数就成了下面这样:

1int main (int argc, const char * argv[]) {
2
3 Man *jimmy = [Man new];
4 [jimmy setName:@"Jimmy"];
5
6 Shoe *black40 =[Shoe new];
7 [black40 setColorAndSize:@"Black" shoeSize:40];
8
9 [jimmy wearShoe:black40];
10
11 Man *mike = [Man new];
12 [mike setName:@"mike"];
13 [mike wearShoe:black40];//mike跟jimmy,现在共同拥有一双40码黑色的鞋子
14
15 [jimmy release];
16 [mike release];
17
18 return 0;
19

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
[Objective-C] Copy 和 MutableCopy发布时间:2022-07-12
下一篇:
【Objective-C】OC中KVO的基本概念和使用方法发布时间:2022-07-12
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap