OC的局部变量在代码块结束时被系统销毁, 内存被回收.
OC的对象, 内部有引用计数器, 当引用计数器的值为0时, 被系统销毁, 内存被回收.
局部变量存放在栈中. 对象存放在堆中.
注意, 对象指针还是存放在栈中, 对象本身占用的内存存放在堆中.
在OC中, 我们要对自己写的继承了NSObject的对象进行内存管理.
对象在建立(alloc, new, copy)时, 引用计数器的值为1.
对象调用retain方法, 引用计数器的值+1.
对象调用release方法, 引用计数器的值-1.
使用retainCount返回引用计数器的值. (unsigned long)
当对象的引用计数器的值为0时, 对象就会被系统销毁, 内存被回收.
对象被销毁时, 系统会调用对象的dealloc方法. 重写dealloc方法释放相关资源, 证实对象被回收. dealloc方法最后要调用[super dealloc];
野指针: 在对象被销毁后, 把指针设为nil. 使用野指针调用方法, 会发生错误.
[main函数中]
每使用alloc, new, copy一次, 就release一次. 并设空指针.
每使用retain一次, 就release一次.
注意: NSString *对象不是alloc产生的, 所以不用release.
当给这个对象设置对象属性时, 要给属性对象的计数器+1.
当这个对象切换对象属性时, 要给原有的属性对象计数器-1, 给新的属性对象计数器+1. 但是要注意新对象和原对象是否是同一个对象.
当这个对象被释放时, 要给它的所有属性对象的计数器-1.
set方法的写法注意:
1 要release原来的属性对象
2 要retain新加的属性对象
3 要判断要替换的属性对象和现有的是否是同一个对象, 如果是, 就不要release
dealloc方法的重写:
1 释放所有的对象类型的属性
2 调用[super dealloc];
3 打印内容, 方便查看是不是所有创建的对象都被释放.
# 使用 @property 的参数生成恰当的set方法
@property的参数:
assign, retain, copy
nonatomic, atomic
readonly, readwrite
setter = setName:, getter = getName
对基本数据类型的属性, 使用assign参数
对OC对象的属性, 使用retain参数
对字符串类型的属性, 通常使用copy参数
使用retain, 编译器会根据@property生成上面那种三行管理内存的setter方法.
使用assign, 编译器会根据@property生成一行直接赋值的setter方法.
使用copy, 编译器会生成使用copy的setter方法, 使得属性是原字符串的拷贝.
因为如果双方在声明中都互相#import, 会造成循环引用.
以后只要一个类包含的属性是另一个类, 在类的声明中使用@class, 在实现中使用#import
@class 类名
这样就声明类,但是如果需要用到该类中的成员变量或者方法,则还需要使用#import
# 释放池
对小内存的对象, 可以使用 @autorelease 代替 release. 使用@autorelease的对象在释放池被销毁时被release一次.
可以在类中提供类方法直接创建autorelease的对象, 注意在新建对象时, 使用 [self alloc] 而不是 [类名 alloc] 以方便子类调用时能够返回子类的对象. 这样的类方法通常以类名开头. 系统自带的这类方法也是带有autorelease的.
[[[类名 alloc] init] autorelease];
上述代码在释放池中,可以不用在最后调用对象的release方法。它会在释放池结束的时候自动让计数器-1.
1 在main函数中
1> 有alloc就要release
2> 有retain 就release
2 对象类型的属性的set方法的三要素:
1> 判断是否是同一对象
2> release原来的对象
3> retain新设的对象, 并设置为属性
4> 注意: 如果两个类互为对方的属性, 一边使用retain, 另一边直接赋值(assign).
3 重写dealloc方法:
1> 释放所有在set方法中retain过的属性
2> 可以打印内容, 方便检查是否所有新建的对象都在程序结束前被释放
3> 要调用[super release];
4 原则
1> 谁alloc, 谁release
2> 谁retain, 谁release
3> 不是自己alloc的就不需要release, 比如很多静态方法创建的对象就不需要release
5 在类的声明中使用@class, 在类的实现中使用#import, 提高效率, 并避免互相循环#import
ARC是编译器特性, 默认指向对象的指针都是强指针, 使用__weak标记的是弱指针. 如果没有强指针指向对象了,这个对象就会被销毁 (编译器会自动添加 retain, release代码). 如果对象被销毁了, 指向它弱指针会被自动清空, 以防野指针错误.
ARC的使用:
1. 即使有alloc也不需要写release或autorelease, 不允许使用retain.
2. set方法对对象类型的属性使用strong代替retain
2. 不需要在dealloc方法中释放属性
也就是说, 有了ARC就不需要关注内存管理了, 怎么写都不会错.