iOS:对象的alloc&init、ARC中dealloc使用

大家好,我是OB!今天来聊聊alloc&init和dealloc!

一、对象的创建:alloc&init

执行Cat *cat = [[Cat alloc]init];时,发生了什么?

alloc开辟一块内存给对象,让它不释放,并且把地址返回给指针。
init对这块内存进行初始化

有下面的继承关系:Cat : Animal Animal : NSObject

@interface Animal : NSObject
@property (nonatomic, strong)NSString *name;
@end

@implementation Animal
- (instancetype)init {
    self = [super init];
    if (self) {
    	self.name = @"我是动物";
    }
    return self;
}
@end

@interface Cat : Animal
@end

@implementation Cat
- (instancetype)init {
    self = [super init];
    if (self) {
    	self.name = @"ob";
    }
    return self;
}
@end

注意:子类Cat中的[super init]并没有给父类Animal开辟内存,子类的[super init]也不会创建父类的实例对象!要不然内存中全是NSObject的实例对象,因为都继承自NSObject。

1、那么[super init]干了些什么呢?

由于[[Cat alloc]init];开辟了一块内存,那么就需要对这块内存进行初始化,不然访问这块内存没有意义。因为继承的原因,需要先到父类那里把成员变量给继承过来,所以需要到父类的init初始化方法 去初始化成员变量,并把父类的成员变量放到子类开辟的内存中。

obj1

结论:所以对象的创建Cat *cat = [[Cat alloc]init];,子类调用[super init]并不会创建父类的实例对象!只是将父类的成员变量搬到子类的实例对象中。所以对象释放时,只需要释放当前对象,父类不需要释放,因为父类没有执行alloc 也没有开辟内存,根本不需要释放。

二、对象的销毁:dealloc

首先来看看dealloc源码的实现

objc_object::rootDealloc() {
    if (isTaggedPointer()) return;  // fixme necessary?
    if (fastpath(isa.nonpointer  &&  
                 !isa.weakly_referenced  &&  
                 !isa.has_assoc  &&  
                 !isa.has_cxx_dtor  &&  
                 !isa.has_sidetable_rc))
    {
        assert(!sidetable_present());
        free(this);
    } 
    else {
        //object_dispose((id)this);
        if (this) {
            // Read all of the flags at once for performance.
            bool cxx = this->hasCxxDtor();
            bool assoc = this->hasAssociatedObjects();
            // This order is important.
            if (cxx) object_cxxDestruct(this);
            if (assoc) _object_remove_assocations(this);
            this->clearDeallocating();
        }
        free(this);
    }
}

可以发现,执行hasCxxDtor(清除成员变量),_object_remove_assocations(清除管理对象)之后,就会free(this),对象的释放就此完成。

结论:对象要释放,必须执行根类NSObject中-(void)dealloc() 方法,因为该方法最终会去执行C++的objc_object::rootDealloc()方法。对象的销毁最终就是在rootDealloc()中销毁

1、MRC 为什么要调用[super dealloc];

首先在MRC环境下,系统不会自动释放对象。
由于对象的释放必须调用c++的rootDealloc()方法。因此一旦我们重写了对象的dealloc方法,如果不调用[super dealloc];那么就不会调用到根类NSObject中-(void)dealloc() 方法。对象也就释放不掉,只是单单执行了该类-(void)dealloc()方法,并没有释放对象

举个例子,如下代码:运行在MRC,注释掉[super dealloc];看看对象是否被释放。

@implementation Cat
- (void)dealloc {
    NSLog(@"self:[%@]-%s",self, __func__);
//    [super dealloc];
}
@end

调用

- (void)viewDidLoad {
    [super viewDidLoad];
    Cat *cat = [[Cat alloc]init];
    cat.name = @"ob";
    NSLog(@"---%@",cat.name);
    [cat release];
    NSLog(@"---%@",cat.name);
}

打印如下:发现执行dealloc()方法后,对象没有被释放

Test[38251:2112405] ---ob
Test[38251:2112405] self:[<Cat: 0x600002b24440>]--[Cat dealloc]
Test[38251:2112405] ---ob

执行[cat release];后,确实来到了[Cat dealloc]方法,但是对象的属性cat.name依然可以使用。也不会crash。就是因为没有调用[super dealloc];导致没有执行根类NSObject中-(void)dealloc() 方法,也就没有执行C++中的objc_object::rootDealloc()方法去释放对象。对象依然存在。

所以MRC一旦重写了-(void)dealloc() 方法一定要调用[super dealloc];,这样才能释放该实例对象。

2、ARC 为什么不能调用[super dealloc];?

ARC如何自动释放?

首先ARC会自动帮我们在代码的适当位置插入[obj release];

[obj release]; 最终会来到根类NSObjectrelease(),此时,会检查对象引用计数是否为0,来判断否调用根类的dealloc()方法。如果为0,那么最后又到了C++的objc_object::rootDealloc()方法,对象就会释放。

我们什么也不做,ARC就调用了一次C++的objc_object::rootDealloc()方法。此时,
如果我们再次调用了[super dealloc];方法,那么最终会调用根类NSObjectrelease()方法,就会会执行到C++的objc_object::rootDealloc()方法,由于ARC已经释放该对象了,这时再次free(this)释放该对象,发生错误。

所以ARC环境下不能调用[super dealloc];,不然会导致该实例对象重复释放

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值