一、set方法的内存管理
接着上篇博文的例子,为Person增加一个属性_age和它的get、set方法。在main.m中声明一新书。如果我们想给Person换一本新书。按照我们的思路,代码是这样的
#import <Foundation/Foundation.h>
#import <a target=_blank class="gpxyarsm" href="#" title="Click to Continue > by MacVx"> book<img src="http://cdncache-a.akamaihd.net/items/it/img/arrow-10x10.png" alt="" /></a>.h"
#import "Person.h"
int main(int argc, const char * argv[])
{
// 创建一本书b1
<a target=_blank class="gpxyarsm" href="#" title="Click to Continue > by MacVx"> book<img src="http://cdncache-a.akamaihd.net/items/it/img/arrow-10x10.png" alt="" /></a> *b1 = [<a target=_blank class="gpxyarsm" href="#" title="Click to Continue > by MacVx"> book<img src="http://cdncache-a.akamaihd.net/items/it/img/arrow-10x10.png" alt="" /></a> alloc] init];
b1.price = 20;
// 创建一个人p
Person *p = [[Person alloc] init];
p.age = 21;
// p拥有b1
p.book = b1;
// 创建新书b2
Book *b2 = [[Book alloc] init];
b2.price = 50;
// p换成新书b2
p.book = b2;
// 释放对象
[b2 release];
b2 = nil;
[b1 release];
b1 = nil;
[p release];
p = nil;
return 0;
}
运行后发现,我们创建了3个对象,却只有两个对象被回收了!之前那本旧书对象没有被回收。这是为什么呢?
我们之前的代码是没有问题的,加了一本新书就出了问题,所以问题就出在p.book=b2;这句话上。分析每个对象的对象计数器。
// 创建一本书b1,b1-1
Book *b1 = [[Book alloc] init];
b1.price = 20;
// 创建一个人p,p1-1
Person *p = [[Person alloc] init];
p.age = 21;
// p拥有b1,b1-2
p.book = b1;
// 创建新书b2,b2-1
Book *b2 = [[Book alloc] init];
b2.price = 50;
// p换成新书b2,b2-2
p.book = b2;
// 释放对象,b2-1
[b2 release];
b2 = nil;
// b1-1
[b1 release];
b1 = nil;
// p-0, b2-0
[p release];
b1运行到最后计数器的值是1,其他的对象都变成了0。原因就在与换书的时候没有release旧书。
解决方法:在Person的set方法中的内容前加入[_car release];
这样,3个对象就都被释放了。
上面的代码看似没有问题了,其实还是有一些漏洞。
先开启僵尸对象检测。点击左上角的项目名称,选择Edit Scheme
勾选“Enable Zommbie Objects”启用僵尸对象
在现实生活中,我们有时候先不想要一个东西,就把这个东西丢了,丢了之后后悔了又想要了。但是在程序中,这样做就会出错。
int main(int argc, const char * argv[])
{
Person *p = [[Person alloc] init];
p.age = 20;
<a target=_blank class="gpxyarsm" href="#" title="Click to Continue > by MacVx"> book<img src="http://cdncache-a.akamaihd.net/items/it/img/arrow-10x10.png" alt="" /></a> *b = [[Book alloc] init];
b.price = 30;
p.book = b;
[b release];
p.book = b;
[b release];
[p release];
return 0;
}
运行发现控制台报了一个经典错误,“message sent to deallocated instance”,这句话的意思是把消息发送给了一个已经销毁的对象,也就是僵尸对象。
同之前一样,分析对象的引用计数器
此时的book和_book都是b。调用[book reatin]方法之前,b的计数器已经变成0了,对象b也被销毁。所以执行一个不存在的对象的方法出错了!
解决方法:在执行[_book release]前加入判断
if (book != _book)
{
[_book release];
}