一、OC内存管理的原理
1.C/C++内存管理的缺陷
实例说明:
int * p1 = malloc(100);
int * p2 = p1;
int * p3 = p1;
Free(p2);
...
Free(p2);
第一次Free(p2),释放内存,因为p1,p2,p3指向的是同一块内存空间地址,释放了p2也就是释放了地址所指向的内存空间,这样p1,p2,p3也就成了野指针。再次使用Free(p2)就会发生段错误。
2.OC对象结构
所有OC对象都有一个计数器(retainCount),保留着当前对象被引用的次数。每一个OC对象被创建后,在占用的内存空间中总有一块4字节的内存空间 (retainCount空间),用来计数当前对象被引用的次数。
3.OC内存管理
每一个OC对象都有一个retainCount计数器,表示当前对象被引用的次数,如果计数为0,才表示真正释放了这个内存。
alloc函数是创建对象时调用的,创建完计数器+1,只会使用一次。
retain函数是对一个对象的计数器+1。
release函数是对一个对象的计数器-1,减到0就会从内存中释放。
OC类实现了引用计数器,对象知道当前被引用的次数。最初对象的计数器是1.
如果需要引用对象,可以给对象发送一个retain消息,这样对象计数器就+1
如果不需要引用对象,可以给对象发送一个release消息,这样对象计数器就-1
当计数器减到0,自动调用对象的dealloc函数,对象从内存中释放。
计数器为0的对象,不能使用release和其他方法。
OC内存管理总结:
1⃣️OC的内存管理机制与.Net和Java那种全自动的垃圾回收机制是完全不同的,本质上还是C语言的手动管理方式,只不过增加了一些自动方法。
2⃣️OC的内存管理是基于引用计数的。要做的事情只是关注计数器引用的次数,而释放内存的工作实际上是由运行环境来完成的。
3⃣️在最简单的情形中,分配的(alloc)对象,保留了(retain)一次对象,那么就需要发送两次release消息,才能释放对象所占内存。
二、内存管理的黄金法则
The basic rule to apply is Everything that increse the reference counter with alloc, copy or retain is in charge of the corresponding [auto]release.
如果你对一个对象使用了alloc、[mutable]copy、retain,那么你就必须使用相应的[auto]release。
计数器+1的方法只有三种:
alloc、[mutable]copy、retain
计数器-1的方法只有一种:
[auto]release
三、retain点语法
1.属性分类
读写权限:
readwrite(缺省):可读可写,可以使用getter和setter
readonly:只读,只能使用getter
如何存储:
assign(缺省)、retain、copy
是否考虑线程:
nonatomic:不用考虑线程安全
重设getter和setter函数名:
getter=...,setter=...
2.为什么使用点语法?
OC内存管理,正常情况下需要大量的retain和release操作,点语法可以减少它们。
Person.h
#import <Foundation/Foundation.h> #import "Dog.h" @interface Person : NSObject { Dog * _dog; } //-(void)setDog:(Dog *)aDog; //-(Dog *) dog; @property (retain)Dog * dog; //这一行代码可以展开为上面的两个方法。 @end
#import "Person.h" @implementation Person //-(void)setDog:(Dog *)aDog{ // if(_dog != aDog){ // [_dog release]; // _dog = [aDog retain]; // } //} //-(Dog *)dog{ // return _dog; //} @synthesize dog = _dog; //这一行代码可以展开为上面的2个方法 -(void)dealloc{ NSLog(@"person is dealloc"); //[_dog release]; //_dog = nil; self.dog = nil; //[self setDog: nil]; [super dealloc]; } @end