黑马程序员-OC内存管理
2014-12-25 10:02
435 查看
[align=center]------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------[/align]
内存管理
1.移动设备的内存极其有限,每个app所能占用的内存是有限制的
2.当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间,比如回收一些不需要使用的对象、变量等
3.管理范围:任何继承了NSObject的对象,结其他基本数据类型(int、char、float、double、struct、enum等)无效
引用计数器
1.每个oc对象都有4个字节的空间用来存储引用计数器
2.每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象
引用计数器的作用
1.当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1
2.当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收,换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已经退出。
引用计数器的操作
1.给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)
2.给对象发送一条release消息,可以使引用计数器值-1
3.可以给对象发送retainCount消息获得当前的引用计数器值
对象的销毁
1.当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收
2.当一个对象被销毁时,系统会自动向对象发送一条dealloc消息
3.一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言
4.一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用
5.不要直接调用dealloc方法
6.一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(即指针错误)
Xcode6找不到Use Automatic Reference Counting
手动关闭arc
新建项目完成后,点击左侧栏里的第一行,标题
这时主界面就会出现很多设置的项目。在上方有一个搜索栏。输入language或者ARC。
在搜索条件将Basic改为All,Combined改为Levels
然后找到Objective-C Automatic Reference Counting 设置为no
就可以使用release等代码了
野指针,指向已回收的对象(不可用内存地址)的指针
//EXC_BAD_ACCESS:访问了一块坏的内存(已经被回收不可用的内存)
打开僵尸对象检测开关:Edit schemes->Run debug->Diagnostics->Memory Management:Objective c Enable Zombie Objects
内存管理原则
1.原则分析
房间原理,只要房间还有人在用,就不会解散
只要还有人在用某个对象,那么这个对象就不会回收
只要你想用这个对象,就让对象的计数器+1
当你不再使用这个对象时,就让对象的计数器-1
当你换房间时,原来房间的对象计数器-1,新房间+1
2.原则规范
如果通过alloc、new或[mutable]copy来创建一个对象,那么必须调用release或 autorelease,不用自己创建的不用管
内存管理代码规范
1.只要调用了alloc,必须有release(autorelease),如果对象不是通过alloc产生的就不需要release
2.set方法的代码规范
1>基本数据类型:直接复制,无需内存管理
2>oc对象类型
- (void)setCar:(Car *)car
{
//1.他判断是不是新传进来对象
if(car!=_car)
{
//2.对旧对象做一次release
[_car release];
//3.对新对象做一次retain
_car = [car retain];
}
}
3.dealloc方法的代码规范
1>一定要[super dealloc],而且放到最后面
2>对self(当前)所拥有的其他对象做一次release
-(void)dealloc
{
[_car release];
[super dealloc];
}
如果调用了retain,无论这个对象是如何生成的,都需要调用release.
property
1.set方法内存管理相关的参数
retain:release旧值 ,retain新值(适用于OC对象类型)
assing:直接赋值(默认,适用于非OC对象类型)
copy:release旧值,copy新值(一般用于NSString)
2.是否要生成set方法
readwrite:同时生成setter和getter的声明、实现
readonly:只会生成getter的声明、实现
3.多线程管理
nonatomic:不加线程锁,性能高(ios一般就用这个)
atomic:加线程锁,性能低(默认)
4.setter和getter方法的名称
setter : 决定了set方法的名称,一定要有个冒号
getter : 决定了get方法的名称(一般用在BOOL类型的get方法,一般以is开头)
5.@property(getter = getWeight) int weight;
6.setHeight,height 同时生成setter和getter的声明、实现
7.@property (readwrite,assign) int height;
//不加锁性能高,直接赋值 age
8.@property (nonatomic,assign) int age;
//内存管理的name
9.@property (retain) NSString *name;
循环引用
当互相引用的时候,使用#import"类.h",类文件将会互相拷贝.
//而且为了提高编译效率,在头文件里并不需要类的全部内容,所以使用@class就足够了。
1.@class的作用:仅仅告诉编译器,某个名称是一个类
@class Person;//仅仅告诉编译器,Person是一个类
2.开发中引用一个类的规范
1>在.h文件中用@class来声明类
2>在.m文件中用#import来包含类的所有东西
3.@class和#import的区别
1> #import方式会包含类的所有信息,包括被引用类的变量和方法;
2> @class方式只是告诉编译器在A.h文件中B *b只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中的信息
3>如果有上面个头文件都#import了同一个文件,或者这些文件依次被#import那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来讲,使用@class方式就不会出现这种问题了
4>在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类。
3.循环retain
1>比如A对象retain了B对象,B对象retain了A对象
2>这样会导致A对象和B对象永远无法释放
解决方案
当两端互相引用时,应该一端用retain,一端用assign
retain:release旧值 ,retain新值(适用于OC对象类型)
assing:直接赋值(默认,适用于非OC对象类型)
autorelease的基本用法
1.autorelease的基本用法
1>会将对象放到一个自动释放池中
2>当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
3>会返回对象本身
4>调用完autorelease方法后,对象的计数器不变
2.autorelease的好处
1>不用再关心对象释放的时间
2>不用再关心什么时候调用release
3.autorelease的使用注意
1>占用内存较大的对象不要随便使用autorelease
2>占用内存较小的时象使用autorelease,没有太大影响
4.自动释放池
1>在ios程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)
2>当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
5.关于系统类
1>系统自带的方法里面没有包含alloc、new、copy,说明返回的对象都是autorelease的
比如不需要的NSString * str = [NSString stringWithFormatL@"age is %d",10];
比如需要的 NSNumber *num = [[NSNumber alloc]initWithInt:10];
[num release]
2>系统规范,方法名以类名开头。
3>OC不允许类同名,不像java可以用包来区别或c#的命名空间。
4>开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象。
6.关于子类
1>如果在person中初始化时,固定初始化person那么,GoodPerson只能得到Person类对象,而如果指定为self那么谁来执行这个类方法以,就可以获得那个类的初始化
2>创建对象时,不要直接用类名,一般用self
例+ (id)person
{
return [[ss[self alloc]init] autorelease];
}
ARC
将非arc代码重构成arc代码:
Edit->
Refactor->Convert to Objective-C ARC ->next->save
使用第三方框架,可能不是arc的,就需要项目中,即需要arc,又可以不用arc
配置个别类,不使用arc:Xcode->s项目配置页,第一个页->Build Phases-类文件-回车或双击,弹出一个对话框,在对话框中输入-fno-bojc-arc
-fno-bojc-arc 不支持arc
-f-bojc-arc 支持arc
ARC判断准则:只要没有强指针指向对象,就会释放对象
ARC特点
1>不允许调用release、retain、retainCount
2>允许重写dealloc,但是不允许调用[super dealloc]
3>@property的参数
* strong : 成员变量是强指针(适用于OC对象类型)
* weak : 成员变量是弱指针(适用于OC对象类型)
* assign : 适用于非OC对象类型
4>使用ARC后,以前的retain改为strong其它一切不变
指针分2种:
1>强指针:默认情况下,所有的指针都是强针 __Strong
2>弱指针:只要没有强指针指向对象,对象被清空,如果对象被清空,弱指针被清空__weak
当指针p=nil时,对象没有指针指向而被释放
相当于,在检测到对象没有指针指向时,被[p release]
__strong Person *p = nil;
__weak Person *p = nil;
@property (nonatomic,strong) Dog *dog;
@property (nonatomic,weak) Dog *dog;
ARC机制下的,写法类似java
当两端循环引用的时候,解决方案:
1>ARC
1端用strong,另1端用weak
2>非ARC
1端用retain,另1端用assign
Person.h->
Person.m->
main.m->
控制台:
2014-11-09 19:44:55.468 01引用计数器[869:303] Person load time:2014/11/09 19:44:55:461
2014-11-09 19:44:55.468 01引用计数器[869:303] Hello, World!
2014-11-09 19:44:55.469 01引用计数器[869:303] p retainCount 1:1,1
2014-11-09 19:44:55.470 01引用计数器[869:303] p retainCount 2:1,2
2014-11-09 19:44:55.471 01引用计数器[869:303] Person 回收了 time:2014/11/09 19:44:55:471
2014-11-09 19:44:55.471 01引用计数器[869:303] p retainCount 3:1,1
2014-11-09 19:44:55.472 01引用计数器[869:303] p retainCount 4:1,0
Person.h->
Person.m->
Book.h->
Book.m->
main.m->
控制台:
2014-11-09 23:15:57.816 02多对象内存管理[1401:303] Hello, World!
2014-11-09 23:15:57.819 02多对象内存管理[1401:303] p retainCount:1
2014-11-09 23:15:57.820 02多对象内存管理[1401:303] b retainCount:2
2014-11-09 23:15:57.820 02多对象内存管理[1401:303] b:1,b2 retainCount:2
2014-11-09 23:15:57.821 02多对象内存管理[1401:303] Book dealloc
2014-11-09 23:15:57.821 02多对象内存管理[1401:303] Book dealloc
2014-11-09 23:15:57.822 02多对象内存管理[1401:303] Person dealloc
Person.h->
Person.m->
Car.h->
Car.m->
main.m->
控制台:
2014-11-10 06:12:56.265 03set方法内存管理[458:303] Hello, World!
2014-11-10 06:12:56.269 03set方法内存管理[458:303] age:20 of Person dealloc
2014-11-10 06:12:56.270 03set方法内存管理[458:303] speed:70 of Car dealloc
2014-11-10 06:12:56.271 03set方法内存管理[458:303] speed:100 of Car dealloc
Person.h->
Person.m->
main.m->
控制台:
2014-11-10 08:22:26.994 04set方法_property[708:303] Hello, World!
2014-11-10 08:22:27.000 04set方法_property[708:303] age:0,rich=1 weight:100 i:2
2014-11-10 08:22:27.001 04set方法_property[708:303] Person dealloc
2014-11-10 08:22:27.003 04set方法_property[708:303] Book dealloc
Person.h->
Person.m->
Card.h->
Card.m->
main.m->
控制台:
2014-11-11 04:07:22.155 05循环引用[388:303] load Person
2014-11-11 04:07:22.159 05循环引用[388:303] load Card
2014-11-11 04:07:22.159 05循环引用[388:303] Hello, World!
2014-11-11 04:07:22.160 05循环引用[388:303] initalize Person
2014-11-11 04:07:22.160 05循环引用[388:303] initalize Card
2014-11-11 04:07:22.161 05循环引用[388:303] dealloc Card
2014-11-11 04:07:22.161 05循环引用[388:303] dealloc Person
Person.h->
Person.m->
GoodPerson.h->
GoodPerson.m->
main.m->
控制台:
2014-11-11 08:37:58.637 06-autorelease[565:303] age:20 Person dealloc
2014-11-11 08:37:58.639 06-autorelease[565:303] age:100 Person dealloc
2014-11-11 08:37:58.640 06-autorelease[565:303] age:102 Person dealloc
2014-11-11 08:37:58.641 06-autorelease[565:303] age:101 Person dealloc
2014-11-11 08:37:58.642 06-autorelease[565:303] money:10 GoodPerson dealloc
2014-11-11 08:37:58.643 06-autorelease[565:303] age:103 Person dealloc
Program ended with exit code: 0
Person.h->
Person.m->
Dog.h->
Dog.m->
main.m->
控制台:
2014-11-11 23:20:01.803 07ARC[627:303] p:<Person: 0x100601a80>
2014-11-11 23:20:01.805 07ARC[627:303] p2-1:<Person: 0x100601a80>
2014-11-11 23:20:01.805 07ARC[627:303] Person dealloc
2014-11-11 23:20:01.806 07ARC[627:303] Person dealloc
2014-11-11 23:20:01.806 07ARC[627:303] p2-2:(null)
2014-11-11 23:20:01.807 07ARC[627:303] p.dog-1:<Dog: 0x1001042f0>
2014-11-11 23:20:01.807 07ARC[627:303] Dog dealloc
2014-11-11 23:20:01.808 07ARC[627:303] p.dog-2:(null)
2014-11-11 23:20:01.809 07ARC[627:303] Person dealloc
Program ended with exit code: 0
[align=center]------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------[/align]
内存管理
1.移动设备的内存极其有限,每个app所能占用的内存是有限制的
2.当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间,比如回收一些不需要使用的对象、变量等
3.管理范围:任何继承了NSObject的对象,结其他基本数据类型(int、char、float、double、struct、enum等)无效
引用计数器
1.每个oc对象都有4个字节的空间用来存储引用计数器
2.每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象
引用计数器的作用
1.当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1
2.当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收,换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已经退出。
引用计数器的操作
1.给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)
2.给对象发送一条release消息,可以使引用计数器值-1
3.可以给对象发送retainCount消息获得当前的引用计数器值
对象的销毁
1.当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收
2.当一个对象被销毁时,系统会自动向对象发送一条dealloc消息
3.一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言
4.一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用
5.不要直接调用dealloc方法
6.一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(即指针错误)
Xcode6找不到Use Automatic Reference Counting
手动关闭arc
新建项目完成后,点击左侧栏里的第一行,标题
这时主界面就会出现很多设置的项目。在上方有一个搜索栏。输入language或者ARC。
在搜索条件将Basic改为All,Combined改为Levels
然后找到Objective-C Automatic Reference Counting 设置为no
就可以使用release等代码了
野指针,指向已回收的对象(不可用内存地址)的指针
//EXC_BAD_ACCESS:访问了一块坏的内存(已经被回收不可用的内存)
打开僵尸对象检测开关:Edit schemes->Run debug->Diagnostics->Memory Management:Objective c Enable Zombie Objects
内存管理原则
1.原则分析
房间原理,只要房间还有人在用,就不会解散
只要还有人在用某个对象,那么这个对象就不会回收
只要你想用这个对象,就让对象的计数器+1
当你不再使用这个对象时,就让对象的计数器-1
当你换房间时,原来房间的对象计数器-1,新房间+1
2.原则规范
如果通过alloc、new或[mutable]copy来创建一个对象,那么必须调用release或 autorelease,不用自己创建的不用管
内存管理代码规范
1.只要调用了alloc,必须有release(autorelease),如果对象不是通过alloc产生的就不需要release
2.set方法的代码规范
1>基本数据类型:直接复制,无需内存管理
2>oc对象类型
- (void)setCar:(Car *)car
{
//1.他判断是不是新传进来对象
if(car!=_car)
{
//2.对旧对象做一次release
[_car release];
//3.对新对象做一次retain
_car = [car retain];
}
}
3.dealloc方法的代码规范
1>一定要[super dealloc],而且放到最后面
2>对self(当前)所拥有的其他对象做一次release
-(void)dealloc
{
[_car release];
[super dealloc];
}
如果调用了retain,无论这个对象是如何生成的,都需要调用release.
property
1.set方法内存管理相关的参数
retain:release旧值 ,retain新值(适用于OC对象类型)
assing:直接赋值(默认,适用于非OC对象类型)
copy:release旧值,copy新值(一般用于NSString)
2.是否要生成set方法
readwrite:同时生成setter和getter的声明、实现
readonly:只会生成getter的声明、实现
3.多线程管理
nonatomic:不加线程锁,性能高(ios一般就用这个)
atomic:加线程锁,性能低(默认)
4.setter和getter方法的名称
setter : 决定了set方法的名称,一定要有个冒号
getter : 决定了get方法的名称(一般用在BOOL类型的get方法,一般以is开头)
5.@property(getter = getWeight) int weight;
6.setHeight,height 同时生成setter和getter的声明、实现
7.@property (readwrite,assign) int height;
//不加锁性能高,直接赋值 age
8.@property (nonatomic,assign) int age;
//内存管理的name
9.@property (retain) NSString *name;
循环引用
当互相引用的时候,使用#import"类.h",类文件将会互相拷贝.
//而且为了提高编译效率,在头文件里并不需要类的全部内容,所以使用@class就足够了。
1.@class的作用:仅仅告诉编译器,某个名称是一个类
@class Person;//仅仅告诉编译器,Person是一个类
2.开发中引用一个类的规范
1>在.h文件中用@class来声明类
2>在.m文件中用#import来包含类的所有东西
3.@class和#import的区别
1> #import方式会包含类的所有信息,包括被引用类的变量和方法;
2> @class方式只是告诉编译器在A.h文件中B *b只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中的信息
3>如果有上面个头文件都#import了同一个文件,或者这些文件依次被#import那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来讲,使用@class方式就不会出现这种问题了
4>在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类。
3.循环retain
1>比如A对象retain了B对象,B对象retain了A对象
2>这样会导致A对象和B对象永远无法释放
解决方案
当两端互相引用时,应该一端用retain,一端用assign
retain:release旧值 ,retain新值(适用于OC对象类型)
assing:直接赋值(默认,适用于非OC对象类型)
autorelease的基本用法
1.autorelease的基本用法
1>会将对象放到一个自动释放池中
2>当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
3>会返回对象本身
4>调用完autorelease方法后,对象的计数器不变
2.autorelease的好处
1>不用再关心对象释放的时间
2>不用再关心什么时候调用release
3.autorelease的使用注意
1>占用内存较大的对象不要随便使用autorelease
2>占用内存较小的时象使用autorelease,没有太大影响
4.自动释放池
1>在ios程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)
2>当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
5.关于系统类
1>系统自带的方法里面没有包含alloc、new、copy,说明返回的对象都是autorelease的
比如不需要的NSString * str = [NSString stringWithFormatL@"age is %d",10];
比如需要的 NSNumber *num = [[NSNumber alloc]initWithInt:10];
[num release]
2>系统规范,方法名以类名开头。
3>OC不允许类同名,不像java可以用包来区别或c#的命名空间。
4>开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象。
6.关于子类
1>如果在person中初始化时,固定初始化person那么,GoodPerson只能得到Person类对象,而如果指定为self那么谁来执行这个类方法以,就可以获得那个类的初始化
2>创建对象时,不要直接用类名,一般用self
例+ (id)person
{
return [[ss[self alloc]init] autorelease];
}
ARC
将非arc代码重构成arc代码:
Edit->
Refactor->Convert to Objective-C ARC ->next->save
使用第三方框架,可能不是arc的,就需要项目中,即需要arc,又可以不用arc
配置个别类,不使用arc:Xcode->s项目配置页,第一个页->Build Phases-类文件-回车或双击,弹出一个对话框,在对话框中输入-fno-bojc-arc
-fno-bojc-arc 不支持arc
-f-bojc-arc 支持arc
ARC判断准则:只要没有强指针指向对象,就会释放对象
ARC特点
1>不允许调用release、retain、retainCount
2>允许重写dealloc,但是不允许调用[super dealloc]
3>@property的参数
* strong : 成员变量是强指针(适用于OC对象类型)
* weak : 成员变量是弱指针(适用于OC对象类型)
* assign : 适用于非OC对象类型
4>使用ARC后,以前的retain改为strong其它一切不变
指针分2种:
1>强指针:默认情况下,所有的指针都是强针 __Strong
2>弱指针:只要没有强指针指向对象,对象被清空,如果对象被清空,弱指针被清空__weak
当指针p=nil时,对象没有指针指向而被释放
相当于,在检测到对象没有指针指向时,被[p release]
__strong Person *p = nil;
__weak Person *p = nil;
@property (nonatomic,strong) Dog *dog;
@property (nonatomic,weak) Dog *dog;
ARC机制下的,写法类似java
当两端循环引用的时候,解决方案:
1>ARC
1端用strong,另1端用weak
2>非ARC
1端用retain,另1端用assign
Person.h->
#import <Foundation/Foundation.h> @interface Person : NSObject @end
Person.m->
#import "Person.h" @implementation Person //当一个Person对象被回收时自动调用这个方法 - (void)dealloc { NSDate *currDate=[NSDate date];//先获取当前时间 //以下两行是创建一个格式化工具,先初始化一个时间格式,然后定义这个格式 NSDateFormatter *dateFormate=[[NSDateFormatter alloc]init]; [dateFormate setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"]; //利用上面的时间格式工具把日期转换成字符串对象格式 NSString *dateStr=[dateFormate stringFromDate:currDate]; NSLog(@"Person 回收了 time:%@",dateStr); //一定要调用父类的回收方法,而且要放在最后面 [super dealloc]; } + (void)load { NSDate *currDate=[NSDate date];//先获取当前时间 //以下两行是创建一个格式化工具,先初始化一个时间格式,然后定义这个格式 NSDateFormatter *dateFormate=[[NSDateFormatter alloc]init]; [dateFormate setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"]; //利用上面的时间格式工具把日期转换成字符串对象格式 NSString *dateStr=[dateFormate stringFromDate:currDate]; NSLog(@"Person load time:%@",dateStr); } @end
main.m->
#import <Foundation/Foundation.h> #import "Person.h" int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World!"); //调用引用计数器 alloc计数器加1 Person *p = [[Person alloc]init]; //类型不匹配需要强转int a = (int),或是使用匹配类型NSInteger int a = (int)[p retainCount]; NSInteger b =[p retainCount]; NSLog(@"p retainCount 1:%d,%ld",a,b); //发送release引用计数器减一,减为零时,对象回收 //验证对象是否回收,重写-dealloc // [p release]; //给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身) //当对象被回收时,再发送retain就不对了。 //retain计数器加1,返回对象本身 [p retain]; b =[p retainCount]; NSLog(@"p retainCount 2:%d,%ld",a,b); [p release]; [p release]; //已回收后多次回收同样报错 //野指针,指向已回收的对象(不可用内存地址)的指针 //EXC_BAD_ACCESS:访问了一块坏的内存(已经被回收不可用的内存) //[p release]; b =[p retainCount]; NSLog(@"p retainCount 3:%d,%ld",a,b); //避免野指针的方法 //变成空指针,空指针指向nil,null,0 p = nil; b =[p retainCount]; NSLog(@"p retainCount 4:%d,%ld",a,b); //当p = nil;后 [p release]就不报错了,因为指针没有指向作何内存 //无效信息,oc没有空指针错误,给空指针发送消息不报错,仅仅是无效警告 [p release]; //打开僵尸对象检测开关:Edit schemes->Run debug->Diagnostics->Memory Management:Objective c Enable Zombie Objects //打开僵尸对象检测开关后 // -[Person setAge:]:message sent to deallocated instance 0x100109a10 //给已经释放的对象发送了一条-setAge:消息; //p.age=10; } return 0; }
控制台:
2014-11-09 19:44:55.468 01引用计数器[869:303] Person load time:2014/11/09 19:44:55:461
2014-11-09 19:44:55.468 01引用计数器[869:303] Hello, World!
2014-11-09 19:44:55.469 01引用计数器[869:303] p retainCount 1:1,1
2014-11-09 19:44:55.470 01引用计数器[869:303] p retainCount 2:1,2
2014-11-09 19:44:55.471 01引用计数器[869:303] Person 回收了 time:2014/11/09 19:44:55:471
2014-11-09 19:44:55.471 01引用计数器[869:303] p retainCount 3:1,1
2014-11-09 19:44:55.472 01引用计数器[869:303] p retainCount 4:1,0
Person.h->
#import <Foundation/Foundation.h> #import "Book.h" @interface Person : NSObject { //当Book是成员变量时,Book无法继承Person Book *_book; } - (void)setBook:(Book *)book; - (Book *)book; @end
Person.m->
#import "Person.h" #import "Book.h" @implementation Person - (void)setBook:(Book *)book { //如果_book没有值,就直接retain如果有值,则将原先的release //可以不加判断直接 release因为oc中空指针发消息不报错 if(_book!=nil){ [_book release]; } _book = [book retain]; } - (Book *)book { return _book; } - (void)dealloc { //对象回收前将所持有的资源处理 [_book release]; NSLog(@"Person dealloc"); [super dealloc]; } @end
Book.h->
#import <Foundation/Foundation.h> @interface Book : NSObject @end
Book.m->
#import "Book.h" @implementation Book - (void)dealloc { NSLog(@"Book dealloc"); [super dealloc]; } @end
main.m->
#import <Foundation/Foundation.h> #import "Person.h" #import "Book.h" int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World!"); //p计数器加1 Person *p = [[Person alloc]init]; //b,b2计数器加1 Book *b = [[Book alloc]init]; Book *b2 = [[Book alloc]init]; NSInteger i = [p retainCount]; NSLog(@"p retainCount:%ld",i); //p调用b b计数器+1 p.book = b; i = [b retainCount]; NSLog(@"b retainCount:%ld",i); //p调用b2,b-1 ,b2+1 p.book = b2; i = [b retainCount]; NSInteger i2 = [b2 retainCount]; NSLog(@"b:%ld,b2 retainCount:%ld",i,i2); [b release]; b = nil; [b2 release]; b2 = nil; //计数器减1 [p release]; p=nil; } return 0; }
控制台:
2014-11-09 23:15:57.816 02多对象内存管理[1401:303] Hello, World!
2014-11-09 23:15:57.819 02多对象内存管理[1401:303] p retainCount:1
2014-11-09 23:15:57.820 02多对象内存管理[1401:303] b retainCount:2
2014-11-09 23:15:57.820 02多对象内存管理[1401:303] b:1,b2 retainCount:2
2014-11-09 23:15:57.821 02多对象内存管理[1401:303] Book dealloc
2014-11-09 23:15:57.821 02多对象内存管理[1401:303] Book dealloc
2014-11-09 23:15:57.822 02多对象内存管理[1401:303] Person dealloc
Person.h->
#import <Foundation/Foundation.h> #import "Car.h" @interface Person : NSObject { int _age; Car * _car; } - (void)setAge:(int)age; - (int)age; - (void)setCar:(Car *)car; - (Car *)car; @end
Person.m->
#import "Person.h" @implementation Person - (void)setAge:(int)age { //基础数据类型不需要管理内存 _age = age; } - (int)age { return _age; } - (void)setCar:(Car *)car { //因为p的车_car和c1相同,而p在setCar中又release所以 c1-1,而之后的retain便不可用了。因为内存无效 //p.car = c1; //解决办法在p setCar中判断如果新车与旧车是同一款,则不进行操作 if(_car!=car){ //因为oc空指针发消息不报错,所以不用判断,直接发回收信息 [_car release]; //将新车赋给人 _car = [car retain]; } } - (Car *)car { return _car; } - (void)dealloc { //回收所拥有的车 [_car release]; NSLog(@"age:%d of Person dealloc",_age); [super dealloc]; } @end
Car.h->
#import <Foundation/Foundation.h> @interface Car : NSObject { int _speed; } - (void)setSpeed:(int)speed; - (int)speed; @end
Car.m->
#import "Car.h" @implementation Car - (void)setSpeed:(int)speed { //基础数据类型不需要管理内存 _speed = speed; } - (int)speed { return _speed; } - (void)dealloc { NSLog(@"speed:%d of Car dealloc",_speed); [super dealloc]; } @end
main.m->
// // main.m // 03set方法内存管理 // // Created by Whome on 14-11-9. // Copyright (c) 2014年 Whome. All rights reserved. // #import <Foundation/Foundation.h> #import "Person.h" #import "Car.h" /* 内存管理代码规范 1.只要调用了alloc,必须有release(autorelease),如果对象不是通过alloc产生的就不需要release 2.set方法的代码规范 1>基本数据类型:直接复制,无需内存管理 2>oc对象类型 - (void)setCar:(Car *)car { //1.他判断是不是新传进来对象 if(car!=_car) { //2.对旧对象做一次release [_car release]; //3.对新对象做一次retain _car = [car retain]; } } 3.dealloc方法的代码规范 1>一定要[super dealloc],而且放到最后面 2>对self(当前)所拥有的其他对象做一次release -(void)dealloc { [_car release]; [super dealloc]; } */ int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World!"); //年龄为20的人 p-1 Person *p = [[Person alloc]init]; p.age =20; //速度为70的车 c-1 Car *c = [[Car alloc]init]; c.speed = 70; //速度为100的车 c1-1 Car *c1 = [[Car alloc]init]; c1.speed = 100; //年龄20的人有了速度70的人 c-2 p.car = c; //年龄20的人有了速度100的人 c-1 c1-2 p.car = c1; //一个不严谨的写法 // c1-1 //[c1 release]; //因为p的车_car和c1相同,而p在setCar中又release所以 c1-1,而之后的retain便不可用了。因为内存无效 //p.car = c1; //解决办法在p setCar中判断如果新车与旧车是同一款,则不进行操作 [p release]; [c release]; [c1 release]; } return 0; }
控制台:
2014-11-10 06:12:56.265 03set方法内存管理[458:303] Hello, World!
2014-11-10 06:12:56.269 03set方法内存管理[458:303] age:20 of Person dealloc
2014-11-10 06:12:56.270 03set方法内存管理[458:303] speed:70 of Car dealloc
2014-11-10 06:12:56.271 03set方法内存管理[458:303] speed:100 of Car dealloc
Person.h->
#import <Foundation/Foundation.h> #import "Book.h" /* 1.set方法内存管理相关的参数 retain:release旧值 ,retain新值(适用于OC 对象类型) assing:直接赋值(默认,适用于非OC对象类型 ) copy:release旧值,copy新值 2.是否要生成set方法 readwrite:同时生成setter和getter的声明、实 现 readonly:只会生成getter的声明、实现 3.多线程管理 nonatomic:不加线程锁,性能高(ios一般就用这 个) atomic:加线程锁,性能低(默认) 4.setter和getter方法的名称 setter : 决定了set方法的名称,一定要有个冒 号 getter : 决定了get方法的名称(一般用在BOOL 类型的get方法,一般以is开头) */ @interface Person : NSObject //(retain):相当于会在set方法中release旧值,retain新值 //缺点dealloc还是需要手写 @property(retain)Book *book; //返回BOOL类型的方法一般以is开头 @property (getter=isRich) BOOL rich; //getter名为getW,setter名为setW @property(getter = ss,setter = qwerq:) int weight; //setHeight,height 同时生成setter和getter的声明、实现 @property (readwrite,assign) int height; //不加锁性能高,直接赋值 age @property (nonatomic,assign) int age; //内存管理的name @property (retain) NSString *name; @end
Person.m->
#import "Person.h"
@implementation Person
/*
@property(retain)Book *book;
等同于
- (void)setBook:(Book *)book
{
if(_book!=book){
[_book release];
_book = [book retain];
}
}
- (Book *)book
{
return _book;
}
*/
- (void)dealloc
{
//回收所拥有的书
[_book release];
NSLog(@"Person dealloc");
[super dealloc];
}
@end
Book.h->
#import <Foundation/Foundation.h> @interface Book : NSObject @end
Book.m->
#import "Book.h"
@implementation Book
- (void)dealloc
{
NSLog(@"Book dealloc");
[super dealloc];
}
@end
main.m->
#import <Foundation/Foundation.h> #import "Person.h" #import "Book.h" int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World!"); Person *p = [[Person alloc]init]; Book *b = [[Book alloc]init]; p.book = b; NSInteger i = [b retainCount]; //p.qwerq不好使 [p qwerq:100]; p.age = 0; p.rich = 1; NSLog(@"age:%d,rich=%d weight:%d i:%ld",p.age,p.isRich,p.ss,i); [p release]; p = nil; [b release]; b = nil; } return 0; }
控制台:
2014-11-10 08:22:26.994 04set方法_property[708:303] Hello, World!
2014-11-10 08:22:27.000 04set方法_property[708:303] age:0,rich=1 weight:100 i:2
2014-11-10 08:22:27.001 04set方法_property[708:303] Person dealloc
2014-11-10 08:22:27.003 04set方法_property[708:303] Book dealloc
Person.h->
#import <Foundation/Foundation.h> //仅标明Card是一个类 @class Card; @interface Person : NSObject //retain:release旧值 ,retain新值(适用于OC对象类型) @property (nonatomic,retain) Card *card; @end
Person.m->
#import "Person.h" #import "Card.h" @implementation Person + (void)initialize { NSLog(@"initalize Person"); } + (void)load { NSLog(@"load Person"); } - (void)dealloc { [_card release]; NSLog(@"dealloc Person"); [super dealloc]; } @end
Card.h->
#import <Foundation/Foundation.h> //仅标明Person是一个类 @class Person; @interface Card : NSObject //assing:直接赋值(默认,适用于非OC对象类型) @property (nonatomic,assign) Person *person; @end
Card.m->
#import "Card.h" #import "Person.h" @implementation Card + (void)initialize { NSLog(@"initalize Card"); } + (void)load { NSLog(@"load Card"); } - (void)dealloc { [_person release]; NSLog(@"dealloc Card"); [super dealloc]; } @end
main.m->
#import <Foundation/Foundation.h> #import "Person.h" #import "Card.h" /* 循环retain 1>比如A对象retain了B对象,B对象retain了A对象 2>这样会导致A对象和B对象永远无法释放 解决方案 当两端互相引用时,应该一端用retain,一端用assign */ int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World!"); //p-1 Person *p = [[Person alloc]init]; //c-1 Card *c = [[Card alloc]init]; //c-2 p.card = c; //p-1 c.person = p; //c-1 [c release]; //p-0 c-0 [p release]; } return 0; }
控制台:
2014-11-11 04:07:22.155 05循环引用[388:303] load Person
2014-11-11 04:07:22.159 05循环引用[388:303] load Card
2014-11-11 04:07:22.159 05循环引用[388:303] Hello, World!
2014-11-11 04:07:22.160 05循环引用[388:303] initalize Person
2014-11-11 04:07:22.160 05循环引用[388:303] initalize Card
2014-11-11 04:07:22.161 05循环引用[388:303] dealloc Card
2014-11-11 04:07:22.161 05循环引用[388:303] dealloc Person
Person.h->
#import <Foundation/Foundation.h> @interface Person : NSObject @property (nonatomic,assign) int age; //简化类初始化写法 + (id)person; //初始化并给成员变量赋值 + (id)personWithAge:(int)age; @end
Person.m->
#import "Person.h" @implementation Person - (void)dealloc { NSLog(@"age:%d Person dealloc",_age); [super dealloc]; } //简化类初始化写法 + (id)person { //如果在person中初始化时,固定初始化person那么,GoodPerson只能得到Person类对象,而如果指定为self那么谁来执行这个类方法以,就可以获得那个类的初始化 return [[[self alloc]init]autorelease]; } //初始化并给成员变量赋值 + (id)personWithAge:(int)age { Person *p = [self person]; p.age = age; return p; } @end
GoodPerson.h->
#import "Person.h" @interface GoodPerson : Person @property (nonatomic,assign) int money; @end
GoodPerson.m->
#import "GoodPerson.h" @implementation GoodPerson - (void)dealloc { NSLog(@"money:%d GoodPerson dealloc",_money); [super dealloc]; } @end
main.m->
#import <Foundation/Foundation.h> #import "Person.h" #import "GoodPerson.h" /* autorelease方法会返回对象本身 调用完autorelease方法后,对象的计数器不变 autorelease会将对象放到一个自动释放池中 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作 */ int main(int argc, const char * argv[]) { //一个内存栈,一般存放占用内存较小的对象 //声明这个代码块是一个自动释放池,当自动释放池销毁时,autorelease的对象将被release @autoreleasepool {//{开始代表创建了释放池 Person *p1 = [[[Person alloc]init]autorelease]; p1.age = 20; }//}结束代表销毁释放池 //自动释放池的其它写法 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; Person *pp = [[[Person alloc]init]autorelease]; pp.age = 100; [pool release]; //将池子清空 //[pool drain]; //简化类初始化写法,初始化成员变量,栈先进后出 @autoreleasepool { Person *pw = [Person person]; pw.age = 101; Person *pw1 = [Person personWithAge:102]; } //常用错误 //1.没有放在@autoreleasepool{}中是无法调用release的 Person *p2 = [[[Person alloc]init]autorelease]; p2.age = 10; //2.发送了两次autorelease,当池销毁时,也会发送两次release,但是在上一次的时候,已经变成野指针了,所以无效 // @autoreleasepool // { // Person *p3 = [[[[Person alloc]init]autorelease] autorelease]; // } //2.当p4发送release后,p4已经成为野指针了,而当池子销毁时,会再一次发送release所以无效。 // @autoreleasepool // { // Person *p4 = [[[Person alloc]init]autorelease]; // // [p4 release]; // } //关于子类细节 @autoreleasepool { //如果在person中初始化时,固定初始化person那么,GoodPerson只能得到Person类对象,而如果指定为self那么谁来执行这个类方法以,就可以获得那个类的初始化 GoodPerson *gp = [GoodPerson personWithAge:103]; // '-[Person setMoney:]: unrecognized selector sent to instance 0x100603970' gp.money = 10; } return 0; }
控制台:
2014-11-11 08:37:58.637 06-autorelease[565:303] age:20 Person dealloc
2014-11-11 08:37:58.639 06-autorelease[565:303] age:100 Person dealloc
2014-11-11 08:37:58.640 06-autorelease[565:303] age:102 Person dealloc
2014-11-11 08:37:58.641 06-autorelease[565:303] age:101 Person dealloc
2014-11-11 08:37:58.642 06-autorelease[565:303] money:10 GoodPerson dealloc
2014-11-11 08:37:58.643 06-autorelease[565:303] age:103 Person dealloc
Program ended with exit code: 0
Person.h->
#import <Foundation/Foundation.h> @class Dog; @interface Person : NSObject //强指针 @property (nonatomic,strong) Dog *dog; @end
Person.m->
#import "Person.h" @implementation Person - (void)dealloc { NSLog(@"Person dealloc"); //ARC不允许,调用父类的dealloc //[super dealloc]; } @end
Dog.h->
#import <Foundation/Foundation.h> @class Person; @interface Dog : NSObject //强指针 @property (nonatomic,strong) Person *person; @end
Dog.m->
#import "Dog.h" @implementation Dog - (void)dealloc { NSLog(@"Dog dealloc"); } @end
main.m->
#import <Foundation/Foundation.h> #import "Person.h" #import "Dog.h" /* ARC判断准则:只要没有强指针指向对象,就会释放对象 ARC特点 1>不允许调用release、retain、retainCount 2>允许重写dealloc,但是不允许调用[super dealloc] 3>@property的参数 * strong : 成员变量是强指针(适用于OC对象类型) * weak : 成员变量是弱指针(适用于OC对象类型) * assign : 适用于非OC对象类型 4>使用ARC后,以前的retain改为strong其它一 切不变 指针分2种: 1>强指针:默认情况下,所有的指针都是强针 __Strong 2>弱指针:只要没有强指针指向对象,对象被清空 ,如果对象被清空,弱指针被清空__weak 当指针p=nil时,对象没有指针指向而被释放相当于,在检测到对象没有指针指向时,被[p release] __strong Person *p = nil; __weak Person *p = nil; ARC机制下的,写法类似java */ int main(int argc, const char * argv[]) { //强指针,默认强指针 __strong Person *p = [[Person alloc]init]; NSLog(@"p:%@",p); //弱指针 __weak Person *p2 =p; NSLog(@"p2-1:%@",p2); p = nil; p2 = nil; //错误写法,因为没有强指针指向类对象,类对象不会存在,类对象不存在,指向类对象的弱指针也会被清空 p2 = [[Person alloc]init]; NSLog(@"p2-2:%@",p2); p = [[Person alloc]init]; Dog *d = [[Dog alloc]init]; p.dog = d; NSLog(@"p.dog-1:%@",p.dog); d = nil; p.dog = d; NSLog(@"p.dog-2:%@",p.dog); //arc的循环引用 //因为都是强指针,所以会导至无法释放,解决办法,将其中d.person变为弱指针,即人不存在了,指针无聊。 p = [[Person alloc]init]; d = [[Dog alloc]init]; p.dog = d; d.person = p; /* 当main结束时首先销毁d,然后销毁p,然后人和狗的类还存在,它们互相强指针,所以都没释放,但是如果将其中一个弱指针,那么被弱指针指向的类对象,就可以被销毁,它的强指针成员也就不存在,那么那个拥有弱指针成员的类对象也就被销毁 */ return 0; }
控制台:
2014-11-11 23:20:01.803 07ARC[627:303] p:<Person: 0x100601a80>
2014-11-11 23:20:01.805 07ARC[627:303] p2-1:<Person: 0x100601a80>
2014-11-11 23:20:01.805 07ARC[627:303] Person dealloc
2014-11-11 23:20:01.806 07ARC[627:303] Person dealloc
2014-11-11 23:20:01.806 07ARC[627:303] p2-2:(null)
2014-11-11 23:20:01.807 07ARC[627:303] p.dog-1:<Dog: 0x1001042f0>
2014-11-11 23:20:01.807 07ARC[627:303] Dog dealloc
2014-11-11 23:20:01.808 07ARC[627:303] p.dog-2:(null)
2014-11-11 23:20:01.809 07ARC[627:303] Person dealloc
Program ended with exit code: 0
[align=center]------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------[/align]
相关文章推荐
- 黑马程序员_OC内存管理
- 黑马程序员_OC内存管理
- 黑马程序员----第六篇 OC内存管理(一)
- 黑马程序员----第七篇 OC内存管理(二)
- 黑马程序员——OC内存管理(非ARC,手工管理)
- 黑马程序员_OC内存管理的总结
- 黑马程序员—OC内存管理
- 黑马程序员_OC内存管理
- 黑马程序员------ios培训 oc内存管理(二)
- 黑马程序员——零基础学习iOS开发——11 OC内存管理
- 黑马程序员——OC内存管理
- 黑马程序员——IOS基础(OC内存管理)
- 黑马程序员-oc内存管理(Q)
- 黑马程序员—IOS加强视频—oc内存管理
- 黑马程序员——IOS基础——OC内存管理
- 黑马程序员——OC内存管理
- 黑马程序员-OC内存管理
- 黑马程序员——OC内存管理
- 黑马程序员-----OC内存管理(一)
- ios黑马程序员--oc内存管理