黑马程序员-OC学习笔记-----内存管理

本文深入探讨iOS应用内存管理的关键概念,包括@property和@synthesize的作用、内存警告处理方式、引用计数器的功能及其操作方法、自动释放池的工作原理以及如何避免循环引用等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

移动设备的内存极其有限,每个app所能占用的内存是有限制的.当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间。比如回收一些不需要使用的对象、变量等。基本的数据类型是放在内存的栈里面,这是不需要我们去管理的,系统会自动回收。但是我们动态分配的内存是在内存的堆里面,这些都是需要我们去管理的,每个对象都应该有着生命周期,从创建的那一刻,就应该有着它凋亡的时候。

@property和@synthesize关键字

@property和@synthesize关键字可以帮助我们构造属性的设置和访问方法即setter和getter方法,可以省去我们很多重复机械的代码。

在声明文件中使用 @property 声明变量,在实现文件中用@synthesize 

@property 关键字可以自动生成某个成员变量的setter和getter方法的声明

@property int age;

编译时遇到这一行,则自动扩展成下面两句:
- (void)setAge:(int)age;
- (int)age;


@synthesize关键字帮助生成成员变量的setter和getter方法的实现。
@synthesize age=_age;

相当于下面的代码:
-(void)setAge:(int)age
{
_age=age;
}


-(int)age
{
Return _age;
}
在新的版本里面@synthesize被抛弃不用了,只要在声明文件里面使用@property声明了变量,那么在实现文件中就不需要用@synthesize了,也能够生成属性的getter和setter方法的实现。


@property关键字的参数介绍

1.控制set方法的内存管理
retain : release旧值,retain新值(用于OC对象)
assign : 直接赋值,不做任何内存管理(默认,用于非OC对象类型)
copy   : release旧值,copy新值(一般用于NSString *)注:对象进行深拷贝,原来的对象进行release操作
 
2.控制需不需生成set方法
readwrite :同时生成set方法和get方法(默认)
readonly  :只会生成get方法
 
3.多线程管理
atomic:性能低(默认)
nonatomic :性能高(一般会使用此参数)
 
4.控制set方法和get方法的名称
setter : 设置set方法的名称,一定有个冒号:
getter : 设置get方法的名称

不同类型的参数可以同时使用,同类型的只能使用一个

声明property的语法为:@property (参数1,参数2) 类型 名字

@property (nonatomic,retain) Person *p;

计数器的引入

每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象
每个OC对象内部专门有4个字节的存储空间来存储引用计数器

对象的结构图:



计数器的作用

当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1
当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已经退出

计数器的操作

给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)
给对象发送一条release消息,可以使引用计数器值-1
可以给对象发送retainCount消息获得当前的引用计数器值


对象的销毁
当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收
当一个对象被销毁时,系统会自动向对象发送一条dealloc消息
一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言
一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用
不要直接调用dealloc方法
一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)

内存管理法则
谁创建,谁release
如果你通过alloc、new或[mutable]copy来创建一个对象,那么你必须调用release或autorelease
换句话说,不是你创建的,就不用你去[auto]release

谁retain,谁release
只要你调用了retain,无论这个对象是如何生成的,你都要调用release


方法的内存管理
如果你有个OC对象类型的成员变量,就必须管理这个成员变量的内存。
1. set方法的实现

- (void)setBook:(Book *)book{
	if (book != _book) {
		[_book release];
		_book = [book retain];
	}
}

2. dealloc方法的实现
- (void)dealloc {
	[_book release];
	[super dealloc];
}

若在成员变量声明的时候使用了retain参数就不需要写setter方法了。

例如:

@property (nonatomic,retain) Book *book;


循环引用

当A、B类相互引用时,会占据着对象让两个对象都无法得到释放。而且直接两个头文件中相互包含编译器会报错的。

在头文件里面使用@class 来声明A、B是类,在实现文件里面用到了哪个就导入其头文件。

解决内存占据不释放的方法:@property关键字一段用retain 另外一端用 assign


autoreleasepool 和autorelease

autoreleasepool 
自动释放池,管理池子中的对象
autorelease
给对象发送autorelease消息时,会将对象存入autoreleasepool,当系统执行完自动释放池时,自动释放池会自动清空池子里边的对象
【注】自动释放池类似于一个数组,进行延迟释放,不会马上计数器减一,而是将当前对象放入最近的自动释放池中,当释放池释放的时候将池中每一个元素都释放一次

自动释放池有着诸多的限制,内存开销过大的不宜使用,但它的存在让我们可以不用怎么太过于注意对象的release时间。

Person *p = [[[Person alloc] init] autorelease];







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值