标签:
------iOS培训、Java培训、Android培训, iOS学习型技术博客,期待与您交流------
内存管理(在对象属性的- setter和- dealloc方法里面写内存管理代码)
内存管理范围:
任何继承自NSObject的对象;其他数据类型(int、char、double、float、struct、enum等)不需要内存管理
对象的引用计数器:
每个OC对象内部都有自己的int类型(占据4个字节)的引用计数器,表示“对象被引用的次数”。
1> 当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认为1
2> 只有当对象的引用计数器为0时,对象占用的堆内存空间才会被系统回收。
引用计数器的操作:
1> 当给对象发送一条retain消息时,可以使引用计数器的值+1(retain方法返回对象本身,该对象的引用计数器值会+1)
2> 当给对象发送一条release消息时,可以使引用计数器的值-1
3> 给对象发送一条retainCount消息可以获取当前对象的引用计数器值
对象的销毁: - dealloc方法(不要自己调用)
1> 当一个对象的引用计数器值为0时,对象就会被销毁,其占用的堆内存空间会被系统回收
2> 当一个对象被销毁时,系统会自动向对象发送一条dealloc消息(即系统会自动调用对象的- dealloc方法,- dealloc方法相当于对象的遗言)
3> 一般会重写- dealloc方法,在重写的- dealloc方法里释放相关资源。- dealloc方法相当于对象的遗言
4> 重写- dealloc时,必须要在最后调用[super dealloc];
野指针和空指针
野指针:
指向僵尸对象(指向已经被回收的,不可用的内存)的指针
野指针错误:// EXC_BAD_ACCESS : 野指针错误,访问了一块坏内存(已经被回收、已经不可用的内存)
空指针:
OC中不存在空指针错误
[nil release]; // OC中不存在空指针错误,给空指针发送消息,不报错,相当于代码[nil release];无效
小结:
1.方法的基本使用:
1> retain :计数器+1,返回对象本身
2> release : 计数器-1,没返回值
3> retainCount : 获取当前计数器
4> dealloc
* 当一个对象计数器为0,被回收销毁的时候,系统自动调用
* 重写dealloc方法一定要在最后调用[super dealloc];
2.概念:
1> 僵尸对象 : 所占用内存已经被回收的对象,不能再使用
2> 野指针 : 指向僵尸对象(不可用内存)的指针。给野指针发送消息报错:EXC_BAD_ACCESS
3> 空指针 : 没有指向任何东西的指针(存储的东西是nil、NULL、0)。给空指针发送消息不会报错,无效
内存管理原则:
1>
* 只要还有人在用某个对象,那么这个对象就不会被回收
* 只要你想用这个对象,就要让这个对象的计数器+1
* 当你不再使用这个对象,就让这个对象的计数器-1
2> 谁创建,谁release
* 如果你通过alloc、new或者(mutable)copy来创建一个对象,就必须调用该对象的release或autorelease
* 也就是说:如果这个对象不是你创建的,就不用你去release或者autorelease
3> 谁retain,谁release
* 只有你调用了对象的retain,最后你都要调用对象的release
总结:
1> 你想使用(占有)某个对象,就应该让该对象的计数器+1(让该对象做一次retain操作)
2> 你不想再使用(占有)某个对象,就应该让对象的计数器-1(让该对象做一次release操作)
3> 谁retain,谁release———谁alloc,谁release
/*
内存管理代码规范:
1.只要调用了alloc,必须有release(autorelease)
换言之:如果对象不是通过alloc产生的,没有调用alloc,就不能有release(autorelease)
2.set方法的代码规范:
1> 基本数据类型:直接赋值
- (void)setAge:(int)age
{
// 基本数据类型不需要管理内存
_age = age;
}
2> OC对象类型
- (void)setBook:(Book *)book
{
if (_book != book) // 1.先判断传进来的是否为新对象
{
// 2.对旧对象(当前使用的对象)进行一次release操作
[_book release];
// 3.再对新对象做一次retain操作
_book = [book retain]; // 你想使用(占有)某个对象,就应该让该对象的计数器+1(让该对象做一次retain操作)
}
// 如果传进来的对象为原来的旧对象(_book == book) 那么什么都不做
}
3.dealloc方法的代码规范:
1> 对self(当前对象)所拥有的其他对象做一次release
2> 一定要在最后调用[super dealloc];
- (void)dealloc
{
[_book release];
[super dealloc];
}
*/
内存管理---@property参数
// @property参数retain : 在自动生成的set方法里,会release旧值,retain新值
// @property参数只会影响setter和getter。
@property (nonatomic, retain) Book *book;
@property (nonatomic, retain) NSString *name;
// 被retain过的属性,必须在dealloc方法中release
// dealloc方法还是要手动重写
- (void)dealloc
{
[_book release];
[_name release];
[super dealloc];
}
总结:
/* @property参数分类
1. set方法内存管理相关参数
* retain : release旧值,retain新值(适用于OC对象类型)
* assign(默认) : 直接赋值(默认,适用于非OC对象类型,比如基本数据类型)
* copy : release旧值,copy新值(适用于OC对象类型)
2. 是否生成set方法
* readwrite(默认) : 同时生成setter和getter的声明、实现
* readonly : 只会生成getter的声明、实现;setter不会
3. 多线程管理
* nonatomic(推荐) : 性能高
* atomic(默认) : 性能低
4. setter和getter方法的名称
* setter : 决定了set方法的名称,一定要有冒号 :
* getter : 决定了get方法的名称(一般用在BOOL类型的get方法)
// 返回BOOL类型的方法名一般以is开头
@property (getter = isRich) BOOL rich;
*/
用来存放数据的类叫做模型类
@class
/*
1.@class作用:
1> 仅仅告诉编译器,某个名称是一个类的名称;能解决循环包含(#import)问题
@class Person; // 仅仅告诉编译器,Person是一个类
2> 提高性能
2.开发中引用一个类的规范:
1> 在.h文件中用@class来声明类
2> 在.m文件中用#import来包含类的所有东西(#import要包含类的.h头文件)
*/
两端(对象) 循环引用(循环retain)
循环retain:A对象retain了B对象,B对象retain了A对象
会导致A对象和B对象永远无法释放
解决方案:
1> 一端用retain
2> 另一端用assign
内存管理-autorelease
/* 以前创建自动释放池对象的方式
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // 等价于 @autoreleasepool{
Person *p = [[[Person alloc] init] autorelease]; // 调用autorelease方法将p放入当前(栈顶)释放池中
[pool release]; // 等价于 }
*/
/*
错误写法:
1> alloc之后调用autorelease,-----又调用release(野指针错误)
2> 连续调用多(n)次autorelease,-------在自动释放池被销毁时,会对该对象做(n)次release操作(野指针错误)
自动释放池子:
1> 在iOS程序运行过程中,会创建无数个自动释放池。这些池子都是以栈结构存在(后进先出(后创建的先销毁))
2> 当一个对象调用autorelease方法时,系统会将这个对象放到栈顶的释放池
*/
// 自动释放池作用:延迟了存放在释放池里面对象的释放时间
// 好处:不用再关心对象释放的时间---不用再关心什么时候做release操作
// 缺点:不能精确的控制对象的销毁时间(因此适用于占用内存较小的对象);占用内存较大的对象不宜使用autorelease
@autoreleasepool
{ // @autoreleasepool{ 代表创建了一个自动释放池对象
Person *p = [[Person alloc] init]; // 此行代码并未将Person对象p放入释放池中
// autorelease方法返回该对象本身
// autorelease会将对象放入一个自动释放池(对象)中
// 调用完autorelease方法后,对象计数器不变
// 当自动释放池(也是个对象)被销毁时,会对池子里面的所有对象做一次release操作
[p autorelease]; // 此时将p放入释放池中 上面两句等价于 Person *p = [[[Person alloc] init] autorelease];
@autoreleasepool // 自动释放池对象可以创建无限个,可以嵌套创建---多个释放池对象以栈形式存放:后进先出(后创建的先销毁)
{
// 调用完autorelease方法后,对象计数器不变。 p2计数器 1
Person *p2 = [[[Person alloc] init] autorelease];
}
// 过了上面一行代码,p2计数器 0 p2对象被回收
} // }代表销毁释放池,此时系统会自动对释放池里面的所有对象自动做一次release操作
#import "Person.h"
/* 总结:
1.系统自带的方法名(以类名开头,不包括前缀)里面没有包含alloc、new、copy,说明返回的对象都是autorelease好了的
2.开发中经常提供一些类方法(以类名开头),快速创建返回一个已经autorelease过的对象
1> 创建对象时不要直接用类名,一般用self
// 自定义一个类方法(以类名开头),快速创建一个已经autorelease好了的对象
+ (id)person
{
return [[[self alloc] init] autorelease]; // 尽量使用self,那样也可以满足继承自它的子类
}
*/
@implementation Person
// 自定义一个类方法(以类名开头),快速创建一个已经autorelease好了的对象
+ (id)person
{
return [[[self alloc] init] autorelease]; // 尽量使用self,那样也可以满足继承自它的子类
}
// 自定义一个类方法(以类名开头),快速创建一个已经autorelease好了的,同时初始化了的对象
+ (id)personWithAge:(int)age
{
//Person *p = [[[Person alloc] init] autorelease];
Person *p = [self person]; // 尽量使用self,那样也可以满足继承自它的子类
p.age = age;
return p;
}
@end
黑马程序员---OC---内存管理(在对象属性的- setter和- dealloc方法里面写内存管理代码)
标签:
原文地址:http://www.cnblogs.com/ithmPeak/p/4401400.html