【基本的内存管理规则】
内存管理模式基于对象的“所有权”上。任何对象都会被有一个或多个使用者引用,只要对象还有一个使用者,该对象就应该继续存在。如果一个对象没有使用者了,系统将自动销毁它。为了让开发者清晰的了解:使用对象和不再使用对象的场景,Cocoa设置了以下策略:
1.管好自己创建的对象。开发者使用alloc、new、copy和mutableCopy来创建对象。
2.使用retain来获得对象的所有权。某个函数接受的对象,通常保证在该函数调用期间仍然可用,并可以安全返回对象给上层调用者。开发者在以下两种情况下使用retain
1)在“访问函数”(accessor)的实现中或者在init方法,为了将对象作为自己的属性。
2)防止对象被其他操作释放掉,从而变为无效的对象。
3.当你不在需要的时候,必须放弃对象所有权。
一个简单的例子
看看下面的代码段,可以证明刚刚的所说的策略
- {
- Person *aPerson = [[Person alloc] init];
- // ...
- NSString *name = aPerson.fullName;
- // ...
- [aPerson release];
- }
Person被通过alloc创建之后,当Person不在使用的时候,发送了一个release的消息。name这个变量没有使用,所以name不必发送release消息。
使用autorelease来发送一个延迟的release
典型的使用场景:函数返回一个对象的时候。例如,你可以像这样实现fullName的方法:
- - (NSString *)fullName {
- NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@",
- self.firstName, self.lastName] autorelease];
- return string;
- }
上面就是典型的场景:你想放弃对象的所有权,但是又想让调用者在string销毁前使用返回值。
还可以通过下面的实现达到上面的效果:
- - (NSString *)fullName {
- NSString *string = [NSString stringWithFormat:@"%@ %@",
- self.firstName, self.lastName];
- return string;
- }
根据命名惯例,full name方法不具备返回值的所有权。因此,调用者无需对返回值string进行release
【系统执行dealloc时间间隔的问题】
大家都知道在ios编程过程中,当一个变量的引用计数变为零的的时候此时retaincount输出他的引用计数会发现是1,像这样
输出引用计数结果为1
[class16 release];
NSLog(@"%ld", [class16 retainCount]);
但是这种情况通常是在对该对象调用release方法后紧接着跟一个NSlog输出他的引用计数, 但是如果你后面接两行同样的NSlog输出的他的引用计数的话或者更多行的时候他会出现崩溃,不过一个很有趣的现象就是崩溃所在的行数是不一定的
大家注意看崩溃时所在的行数
我们会发现他会存在一个随机性,大家知道当一个对象的引用计数为0的时候,程序会自动调用dealloc函数将其销毁,如果销毁之后你再对其进行任何操作都会崩溃,就像上图那样,但是系统调用dealloc函数和我们自己写的NSlog输出函数会存在一个时间先后的问题,这也就是我们运行结果随机性的根源,如果你的NSlog在系统调用dealloc之前被调用,那么就会正常显示1,如果在其之后那么就会崩溃,打个比方假如系统在计数变为零后一秒后调用dealloc,那么在这一秒之内所有的对其操作都会有显示,一旦一秒过了就会产生崩溃,而具体是多长时间之后才调用,这取决你系统本身,代码量以及很多因素,那么我由此想到,即使第一种情况只有紧接着一行的NSlog也不一定是百分之百可以成功的,对此我试了执行100次其中有8次会产生崩溃,几率是很小的,但是也证明了不是百分之百能成功的,我说这个也就是希望大家明白一下内存管理的机制
【实现dealloc放弃对象的所有权】
NSObject类定义了一个方法dealloc,当某个对象没有使用者,并它的内存是可再生的,delloc就自动被调用。delloc的角色就是释放对象占用的内存并且处理自己所拥有的资源,包括本身变量的释放。
下面的代码展示了,如何实现Person类的dealloc函数。
- @interface Person : NSObject
- @property (retain) NSString *firstName;
- @property (retain) NSString *lastName;
- @property (assign, readonly) NSString *fullName;
- @end
- @implementation Person
- // ...
- - (void)dealloc
- [_firstName release];
- [_lastName release];
- [super dealloc];
- }
- @end