在前面, 我们知道了OC中内存管理的机制, 引用计数, 也对引用计数有了基本的认识, 有些人可能会说, 引用计数而已, 不就是+1, -1么, 有多难? 的确, 在单个对象中的操作的确不难, 但如果是在多个对象之间操作呢? 这个就难了, 为什么这么说? 下面我们来看看示意图:
在示例图中, 有两个对象在调用Book, 那么Book的引用计数就为2, 每当释放一个对象Book的引用计数就-1, 其实这个关系到一些比较复杂的操作, 如果你释放了Student对象, 并没有把它的指针也清零, 那么Book这个对象就不会被释放, 一直存在于内存中, 当然, 只释放Person对象也是一样, 所以在我们需要思考更多的问题, 看看哪个对象没有被释放, 哪个对象的指针没有清零等等....
前面我们也说过, 谁通过alloc,new, copy或者[mutable]copy等方法创建, 那么就必须得调用release, 或者autorelease去释放对象, 这里有几个方法我们暂时没讲, 先不去理会.
还有一点就是谁retain, 那么就是谁release, 有始有终, 有增有减, 曾经让对象+1, 那么最后就必须让对象-1.
来看看代码例子:
<span style="font-size:12px;">#import <Foundation/Foundation.h> @interface Person : NSObject { Book *_book; } - (void)setBook:(Book *)boook; - (Book *)book; @end @implementation Person - (void)setBook:(Book *)boook { _book = book; } - (Book *)book { return _book; } @end</span>
<span style="font-size:12px;">#import <Foundation/Foundation.h> @interface Book : NSObject { int _price; } - (void)setPrice:(int)price; - (int)price; @end @implementation Book - (void)setPrice:(int)price { _price = price; } - (int)price { return _price } @end</span>
#import <Foundation/Foundation.h> #import "Book.h" #import "Person.h" int main() { Book *b = [[Book alloc] init]; Person *p = [[Person alloc]init]; [b release]; b = nil; [p release]; p = nil; return 0; }
经过我们这么一些, 那么首先消失的就是b这个对象, 并且它的指针也会清零, 那么Book这个对象就会被释放, 看上去貌似没问题, 其实问题大大滴, 下面我们看看释放后的示意图:
PS: b指向Book对象的这根线是虚线, 代表的是已经被清零.
按照例子来讲, 我们所画的示意图就是和例子一样的结果, Book对象是被释放了, 但在Person对象里面, 还有一个_book指向着Book对象, 在这样子的情况下, 合理吗? 答案肯定是否定的.
那么我们应该怎么做呢?
<span style="font-size:12px;">@implementation Person - (void)setBook:(Book *)boook { _book = [book retain]; } - (Book *)book { return _book; } - (void)dealloc { [_book release]; NSLog(@"对象被释放了"); [super dealloc]; } @end</span>
只有这样子, 才可以使得Book被释放的时候, _book还有效, 并且只有通过Person对象被释放, 才可以完全的把Book对象给释放.
原理就是:
这样子我们就遵循了内存管理的原则, 永远都不会有错, 而一当b对象不想拥有Book对象的时候, 那么就可以释放, 并且清空它的指针, 但Person对象还拥有Book, 所以Book对象的计数器是1, 这样子程序就不会产生内存泄漏.
最后, p对象也release了, 那么Book对象和Person对象的计数器都变为0, 全部对象被释放, 并且指针清零, 非常严禁的内存管理.
好了, 这次我们就讲到这里, 下次我们继续~~