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 //
// Sample.h
// MemoryManage_1
//
// Created by jimmy.yang on 11-2-19.
// Copyright 2011 __MyCompanyName__. All rights reserved.
// #import <Foundation/Foundation.h> @interface Sample : NSObject { } @end
类实现部分Sample.m //
// Sample.m
// MemoryManage_1
//
// Created by jimmy.yang on 11-2-19.
// Copyright 2011 __MyCompanyName__. All rights reserved.
// #import "Sample.h" @implementation Sample -(id) init
{
if (self=[super init]){
NSLog(@"构造函数被调用了!当前引用计数:%d",[self retainCount]);
}
return (self);
} -(void) dealloc{
NSLog(@"析构函数将要执行...,当前引用计数:%d",[self retainCount]);
[super dealloc];
}
@end
代码很简单,除了"构造函数"跟"析构函数"之外,没有任何其它多余处理。 主程序调用 #import <Foundation/Foundation.h>
#import "Sample.h" int main (int argc, const char * argv[]) { Sample *_sample = [Sample new]; //构造函数被调用了!当前引用计数: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];//析构函数将要执行...,当前引用计数:1
NSLog(@"_sample.retainCount=%d",[_sample retainCount]);//1,注:即便是在析构函数执行后,如果立即再次引用对象的retainCount,
仍然返回1,但以后不管再试图引用该对象的任何属性或方法,都将报错
NSLog(@"_sample.retainCount=%d",[_sample retainCount]);//对象被释放之后,如果再尝试引用该对象的任何其它方法,则报错
//[_sample retain];//同上,会报错 return 0;
}
这段代码主要验证:对象刚创建时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 以上结论是实际试验得出来的,见下面的代码: 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]);//报错:Program received signal: “EXC_BAD_ACCESS”.
s = nil;
NSLog(@"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接口定义部分 #import <Foundation/Foundation.h> @interface Shoe : NSObject {
NSString* _shoeColor;
int _shoeSize;
} //鞋子尺寸
-(void) setSize:(int) size;
-(int) Size; //鞋子颜色
-(void) setColor:(NSString*) color;
-(NSString*) Color; //设置鞋子的颜色和尺码
-(void) setColorAndSize:(NSString*) pColor shoeSize:(int) pSize; @end
Shoe.m实现部分 //
// Shoe.m
// MemoryManage_1
//
// Created by jimmy.yang on 11-2-19.
// Copyright 2011 __MyCompanyName__. All rights reserved.
// #import "Shoe.h" @implementation Shoe //构造函数
-(id)init
{
if (self=[super init]){
_shoeColor = @"black";
_shoeSize = 35;
}
NSLog(@"一双 %@ %d码 的鞋子造好了!",_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];
} //析构函数
-(void) dealloc
{
NSLog(@"%@ %d码的鞋子正在被人道毁灭!",_shoeColor,_shoeSize);
[super dealloc];
} @end
Man.h定义部分 //
// Man.h
// MemoryManage_1
//
// Created by jimmy.yang on 11-2-20.
// Copyright 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实现部分 //
// Man.m
// MemoryManage_1
//
// Created by jimmy.yang on 11-2-20.
// Copyright 2011 __MyCompanyName__. All rights reserved.
// #import "Man.h" @implementation Man //构造函数
-(id)init
{
if (self=[super init]){
_name = @"no name";
}
NSLog(@"新人\"%@\"出生了!",_name);
return (self);
} -(void) setName:(NSString *)newName
{
_name =newName;
} -(NSString*)Name
{
return _name;
} -(void) wearShoe:(Shoe *)shoe
{
_shoe = shoe;
} //析构函数
-(void) dealloc
{
NSLog(@"\"%@\"要死了! ",_name);
[super dealloc];
} @end
main函数调用 #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; }
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()方法,改成下面这样: +
即:在Man被销毁的时候,先把_shoe给销毁。这样在main()函数中,就不再需要单独写一行[black40 release]来释放black40了. 现在又有新情况了:jimmy交了一个好朋友mike,二人成了铁哥们,然后jimmy决定把自己的鞋子black40,跟mike共同拥有,于是main函数就成了下面这样: +
麻烦来了:jimmy在挂掉的时候(即[jimmy release]这一行),已经顺手把自己的鞋子也给销毁了(也许他忘记了mike也在穿它),然后mike在死的时候,准备烧掉自已的鞋子black40,
却被告之该对象已经不存在了。于是程序运行报错: Running…
2011-02-23 13:38:53.169 MemoryManage[374:a0f] 新人"no name"出生了!
2011-02-23 13:38:53.176 MemoryManage[374:a0f] 一双 black 35码 的鞋子造好了!
2011-02-23 13:38:53.177 MemoryManage[374:a0f] 新人"no name"出生了!
2011-02-23 13:38:53.179 MemoryManage[374:a0f] "Jimmy"要死了!
2011-02-23 13:38:53.181 MemoryManage[374:a0f] Black 40码的鞋子正在被人道毁灭!
2011-02-23 13:38:53.183 MemoryManage[374:a0f] "mike"要死了!
Program received signal: “EXC_BAD_ACCESS”.
sharedlibrary apply-load-rules all
(gdb) 上面红色的部分表示程序出错了:Bad_Access也就是说访问不存在的地址。 最解决的办法莫过于又回到原点,Man.m的dealloc中不连带释放Shoe实例,然后把共用的鞋子放到main函数中,等所有人都挂掉后,
最后再销毁Shoe实例,但是估计main()函数会有意见了:你们二个都死了,还要来麻烦我料理后事。 举这个例子无非就是得出这样一个原则:对于new出来的对象,使用retain造成的影响一定要运用相应的release抵消掉,
反之亦然,否则,要么对象不会被销毁,要么过早销毁导致后面的非法引用而出错。

(转)IOS内存管理 retain release的更多相关文章

  1. iOS内存管理retain,assign,copy,strong,weak

    转自:http://www.cnblogs.com/nonato/archive/2013/11/28/3447162.html iOS的对象都继承于NSObject, 该对象有一个方法:retain ...

  2. iOS 内存管理-copy、 retain、 assign 、readonly 、 readwrite、nonatomic、@property、@synthesize、@dynamic、IB_DESIGNABLE 、 IBInspectable、IBOutletCollection

    浅谈iOS内存管理机制 alloc,retain,copy,release,autorelease 1)使用@property配合@synthesize可以让编译器自动实现getter/setter方 ...

  3. iOS内存管理

    iOS内存管理的方式是引用计数机制.分为MRC(人式引用计数)和ARC(自动引用计数). 为什么要学习内存管理? 内存管理方式是引用计数机制,通过控制对象的引用计数来实现操作对象的功能.一个对象的生命 ...

  4. 【Bugly干货分享】iOS内存管理:从MRC到ARC实践

    Bugly 技术干货系列内容主要涉及移动开发方向,是由Bugly邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,转载请标明出处. 对于iOS程序员来说,内存管理是入门的 ...

  5. IOS内存管理学习笔记

    内存管理作为iOS中非常重要的部分,每一个iOS开发者都应该深入了解iOS内存管理,最近在学习iOS中整理出了一些知识点,先从MRC开始说起. 1.当一个对象在创建之后它的引用计数器为1,当调用这个对 ...

  6. iOS内存管理编程指南

    iOS 内存管理 目录[-] 一:基本原则 二:成员变量的内存管理 三:容器对象与内存管理 四:稀缺资源的管理 五:AutoRelease 六:其他注意事项 iOS下内存管理的基本思想就是引用计数,通 ...

  7. iOS内存管理(一)

    最近有时间,正好把iOS相关的基础知识好好的梳理了一下,记录一下内存相关方面的知识. 在理解内存管理之前我觉得先对堆区和栈区有一定的了解是非常有必要的. 栈区:就是由编译器自动管理内存分配,释放过程的 ...

  8. IOS内存nil与release的区别

      IOS内存nil与release的区别   分类: IOS内存管理 nil和release的作用: nil就是把一个对象的指针置为空,只是切断了指针与内存中对象的联系:而release才是真正通知 ...

  9. iOS内存管理 ARC与MRC

    想驾驭一门语言,首先要掌握它的内存管理特性.iOS开发经历了MRC到ARC的过程,下面就记录一下本人对iOS内存管理方面的一些理解. 说到iOS开发,肯定离不开objective-c语言(以下简称OC ...

随机推荐

  1. 《Introduction to Algorithm》-chaper33-计算几何学

    叉积: 在平面中我们为了度量一条直线的倾斜状态,为引入倾斜角这个概念.而通过在直角坐标系中建立tan α = k,我们实现了将几何关系和代数关系的衔接,这其实也是用计算机解决几何问题的一个核心,计算机 ...

  2. oracle flashback

    一.Flashback闪回技术概述:当Oracle数据库发生逻辑错误时,必须使用flashback技术,实现快速和方便的恢复数据.对于人为错误,要确定受到错误事务影响的对象或者记录是非常困难的.使用f ...

  3. OutLook中发送用户密码加密的小技巧

    1     在左上栏目里面选择  New E-mail选项卡,点击进入发送新邮件页面. 2    在第一栏选择Options选项,点击打开 3    看到有一个红色按钮Perssion按钮,打开 4 ...

  4. 如何调试什么时候SaveFileDialog会被Dispose

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:如何调试什么时候SaveFileDialog会被Dispose.

  5. Java 解析epub格式电子书,helloWorld程序,附带源程序和相关jar包

    秀才坤坤出品 一.epub格式电子书 相关材料和源码均在链接中可以下载:http://pan.baidu.com/s/1bnm8YXT 包括 1.JAVA项目工程test_epub,里面包括了jar包 ...

  6. 使用dispatch_once:创建单列

    无论是爱还是恨,你都需要单例.实际上每个iOS或Mac OS应用都至少会有UIApplication或NSApplication. 什么是单例呢?Wikipedia是如此定义的: 在软件工程中,单例是 ...

  7. 数字信号处理与音频处理(使用Audition)

    前一阵子由于考博学习须要,看了<数字信号处理>,之前一直不清除这门课的理论在哪里应用比較广泛. 这次正巧用Audition处理了一段音频,猛然发现<数字信号处理>这门课还是很实 ...

  8. \\ip 映射 指定的网络名不再可用

    问题:\\ip 映射  指定的网络名不再可用 解决方法:服务器端打开服务列表  services.msc 启动两个进程 1.Computer Browser 2. Workstation 就正常了~~ ...

  9. Could not find class &#39;****&#39;, referenced from method #####

    找不到类,多半也是和第三方的jar包有关. 将找不到的类.在下图中的地方勾选出来.假设jar太多.有的类有冲突的话,须要明白其先后顺序. 请外一篇和第三方jar有关的异常的文章. Conversion ...

  10. gallery左右滑动时图片淡入淡出

    前几天,公司项目有一个功能要做成滑动图片的淡入淡出,要一边滑动一边改变,所以ViewFlipper左右滑动效果就不能了.网上找了很久,也找不到资料,所以自己写了一个,通过滑动改变imageView的透 ...