手动管理内存
retain计数是一个相当简单的概念,Objective-C中的内一个对象都有一个retain计数。retain计数是一个整数。使用alloc函数创建一个对象时,该对象的retain计数设为1.当计数变为0的时候,对象被释放。一般通过发送retain消息给对象,从而增加对象的retain计数。发送release给对象,则减少retain计数的值。
手动管理内存前,先进入项目的“Build Settings” 里面,找到“Objective-C Automatic Reference Counting” 设置为 “No”
例如我们要对一个Person类进行手动的内存管理:
接口文件
//Person.h
#import
@interface Person : NSObject
{
NSString *_name;
}
-(void)setName:(NSString *)name;
-(NSString *)name;
@end
实现文件:
//Person.m
#import "Person.h"
@implementation Person
-(void)setName:(NSString *)name
{
_name = name;
}
-(NSString *)name
{
return _name;
}
-(void)dealloc
{
NSLog(@"内存清理.");
[super dealloc];
}
@end
主文件:
//main.m
#import
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *person = [[Person alloc] init];
[person setName:@"Mr.柿子"];
NSString *getName = [person name];
//计数器-1
[person release];
[getName release];
NSLog(@"The name is %@",getName);
}
return 0;
}
Accessor 方法
当变量是常规的int类型方法时,可以创建简单的accessor方法
//Get Method
-(int) food
{
return food;
}
//Set Method
-(void)setFood:(int)x
{
food = x;
}
但是当变量是一个指针类型的时候,就需要使用常规的3用法了。
第一个用法:retain,然后再释放
Objective-C
-(void)setFood:(NSDate *)x
{
[x retain];
[food release];
food = x;
}
注意:如果这两个对象指向同一对象,那么进行retain和释放就是多余的。
第二个用法:改变前先检查
-(void)setFood:(NSDate *)x
{
if(food != x){
[food release];
food = [x retain];
}
}
缺陷:必须执行一次额外的if语句。
第三个用法:自动释放旧的对象
Objective-C
-(void)setFood:(NSDate *)x
{
[food autorelease];
food = [x retain];
}
注意:如果存在retain计数错误的情况,就必须等循环结束后才能发现,这样不利于跟踪。前两个方法在程序崩溃的时候就很容易找到原因。
ARC 内存管理
尽管手动引用计数很简单,但是想要程序顺利的执行却很困难。实际上,这样的方法虽然减少了内存泄露,但是却带来了程序崩溃,出错的问题。
使用ARC后,我们将无须再需要去关注对象的retain计数,二将更多的关注点放在这些对象的关系上。
对象之间的关系就是引用,而引用类型有2种,分别是:强引用和弱引用。
强引用
默认情况下的引用都是强引用。
我们只需要像平常来使用,ARC解决dealloc中强引用的释放问题,我们也可用使用dealloc方法来解决其他的内存清理问题。
弱引用
弱引用与旧的手动引用计数指针相似:没有隐式的retain,指针值只在内存中修改。
然而这样的引用一直是引起程序崩溃的原因。假如指针没有被retain,这个对象就被分配,那么将留下一句僵尸指针,以后使用时,就是一个潜在的引起崩溃的原因。
ARC解决这个问题的方法是指针指向的对象被重新分配时,字段蒋弱引用设为nil,这就是所谓的“Zeroing Weak reference”.
什么时候使用弱引用?
当遇到了两个对象相互retain,最终导致永远都不会被释放。这个在ARC中叫做强引用循环。
怎么避免呢?
通过有技巧的使用弱引用,可避免这样的引用循环。
@interface Person : NSObject
{
Person *parent; //错了~,这导致了强引用循环
NSMutableArray *children;
}
@end