Objective-C内存管理详解

作者:袖梨 2022-06-25


手动管理内存

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

相关文章

精彩推荐