当前位置: 移动技术网 > 移动技术>移动开发>IOS > iOS:对象的alloc&init、ARC中dealloc使用

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

2020年07月17日  | 移动技术网移动技术  | 我要评论

大家好,我是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会自动帮我们在代码的适当位置插入[obj release];,对象引用计数为0就会自动释放,其实release()底层也是调用对象的dealloc()方法。如果我们调用了[super dealloc];方法,那么由上可知,最终会执行到C++的objc_object::rootDealloc()方法,这时对象就free(this)释放了,然后ARC自动释放机制又会调用我们对象的dealloc()方法,最后又到了C++的objc_object::rootDealloc()方法,就会重复free(this)释放,导致未知错误

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

本文地址:https://blog.csdn.net/pk_sir/article/details/107384255

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网