说一说基类 NSObject(二)

本节我们继续学习NSObject,这个类中的很多方法都是我们常用的,所以要重点学习,花点时间也是值得的。

一、实例对象的生成和释放相关方法
1. alloc

类方法alloc,声明在NSObject类中。

+(instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");

作用是生成消息接收类的实例对象,为实例对象开辟存储空间, 并初始化对象。之前alloc负责分配内存空间,init负责对对象进行初始化操作。通过实验我们知道,现在alloc方法就可以完成开辟空间和初始化的操作。

实际上,现在的alloc和new方法是一个意思了。

验证之前,我们先新建一个target,新建一个类ClassA,如下图:


说一说基类 NSObject(二)_第1张图片
image.png

classA.h

@interface ClassA : NSObject

@property(nonatomic, copy)NSString * name;

-(void)hello;

@end

classA.m

#import "ClassA.h"

@implementation ClassA

-(void)hello {
    NSLog(@"你好,我是A类的对象,我的名字是%@", self.name);
}

@end

alloc验证代码:
在main.m中的main方法的自动释放池中添加代码:

       ClassA * a = [ClassA alloc];
        a.name = @"小雨滴";
        NSLog(@"alloc a = %@, name = %@",a, a.name);
        [a hello];
        
        ClassA * a2 = [ClassA new];
        a2.name = @"小雪花❄️";
        [a2 hello];

打印结果:


image.png
2.dealloc

对象方法dealloc声明在NSObject类中
- (void)dealloc OBJC_SWIFT_UNAVAILABLE("use 'deinit' to define a de-initializer");
作用是,释放实例对象。我们知道,当对象的引用计数为0的时候,对象就会被释放了,对象实际释放是在
dealloc方法中进行的。程序不允许直接调用这个方法。允许子类中重写这个方法,当对象释放的时候,
这个方法会被调用。

我们在ClassA.m文件中重写dealloc方法

- (void)dealloc
{
    NSLog(@"A的对象 %@ , %@ 被销毁了",self, self.name);
}

再次运行,看看打印结果

说一说基类 NSObject(二)_第2张图片
image.png

因为我们是把对象a和a2写在自动释放池中的,所以自动释放池走完的时候,对象a,a2就会被释放了,dealloc方法就被调用了。
我们在自动释放池外面在定义一个对象看看结果如何。

//
//  main.m
//  Lesson8_2
//
//  Created by wenhuanhuan on 2020/2/22.
//  Copyright © 2020 weiman. All rights reserved.
//

#import 
#import "ClassA.h"

int main(int argc, const char * argv[]) {
    
    ClassA * outA = [ClassA alloc];
    outA.name = @"外部A";
    
    @autoreleasepool {

        ClassA * a = [ClassA alloc];
        a.name = @"小雨滴";
        NSLog(@"alloc a = %@, name = %@",a, a.name);
        [a hello];
        
        ClassA * a2 = [ClassA new];
        a2.name = @"小雪花❄️";
        [a2 hello];
    }
    [outA hello];
    
    return 0;
}

看看打印结果:


说一说基类 NSObject(二)_第3张图片
image.png
3. release、retain、autorelease、retainCount

这几个方法都是关于内存管理的,手动内存管理(MRC)的时候用于增加引用计数,减少引用计数,返回引用计数。ARC中,这几个方法不可用。简单了解下。
这几个方法都是声明在NSObject协议中的。


说一说基类 NSObject(二)_第4张图片
image.png

-(instancetype)retain OBJC_ARC_UNAVAILABLE;
给对象的引用计数加1,同时返回对象。
-(oneway void)release OBJC_ARC_UNAVAILABLE;
给对象的引用计数减1。
-(instancetype)autorelease OBJC_ARC_UNAVAILABLE;
把对象加入到自动释放池中,同时返回对象。
-(NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;
返回对象的引用计数。

4.finalize

这个方法是垃圾回收机制中使用的方法,垃圾回收器在释放对象之前会执行finalize方法,有点像dealloc方法。
垃圾回收是指在程序运行过程中,不定时的检查是否有不再使用的对象,如果有就释放它。目前,垃圾回收内存管理方式只用在Mac OS X的软件中,Mac OS X10.7和iOS5以上系统推荐使用ARC进行内存管理。我们这里不再仔细深究。


image.png

从截图上我们看到,OC的垃圾回收机制已经不再支持。(我使用的Xcode版本是 Version 11.3.1 (11C504))。

5.init

init方法是对对象进行初始化的,实验证明,目前可以省略这个方法。子类可以重写这个方法。
这个方法的源码如下:

    - (id)init {
         return _objc_rootInit(self);
     }

     id _objc_rootInit(id obj)
     {
         return obj;
     }

我们可以发现,这个init方法什么都没干呀,所以是可以省略咯。

init方法可以被重写,来实现自己想要在初始化的时候自定义的内容。
我们在ClassA中写一下验证代码:
ClassA.h

@interface ClassA : NSObject

@property(nonatomic, copy)NSString * name;
@property(nonatomic, assign)int age;
@property(nonatomic, copy)NSString * remark;

-(instancetype)init;
-(void)hello;
-(void)printAllProperty;

@end

ClassA.m

#import "ClassA.h"

@implementation ClassA

-(instancetype)init {
    if (self = [super init]) {
        self.name = @"无名氏";
        self.remark = @"default";
    }
    return self;
}

-(void)hello {
    NSLog(@"你好,我是A类的对象,我的名字是%@", self.name);
}

-(void)printAllProperty {
    NSLog(@"self = %@ :", self);
    NSLog(@"name = %@, age = %d, remark = %@",
            self.name, self.age, self.remark);
}

- (void)dealloc
{
    NSLog(@"A的对象 %@ , %@ 被销毁了",self, self.name);
}

@end

main中:

       ClassA * a3 = [[ClassA alloc] init];
        NSLog(@"赋值前 a3: ");
        [a3 printAllProperty];
        a3.name = @"小云朵☁️";
        a3.age = 20;
        a3.remark = @"白白的云";
        NSLog(@"赋值后 a3: ");
        [a3 printAllProperty];
        
        ClassA * a4 = [ClassA alloc];
        NSLog(@"只用alloc创建的对象a4: ");
        [a4 printAllProperty];

打印结果:


说一说基类 NSObject(二)_第5张图片
image.png

从打印结果可以看出,此时,只用alloc创建的对象和使用init初始化的对象是不一样的,只用alloc创建的对象不会走重写的init方法。

6.initialize方法
类方法initialize,定义在NSObject类中。
+(void)initialize;
这个方法用于类的初始化。这个方法会在类收到第一个消息之前被自动执行。

我们在ClassA的实现方法中,重写这个方法。

+ (void)initialize
{
    if (self == [ClassA class]) {
        NSLog(@"ClassA 被初始化了");
    }
}

执行结果:


说一说基类 NSObject(二)_第6张图片
image.png

我们发现,这个方法是最先执行的。

之前认为,这个方法不可以手动调用的,实验发现,是可以被手动调用的。


说一说基类 NSObject(二)_第7张图片
image.png

看看打印:


说一说基类 NSObject(二)_第8张图片
image.png

也是被成功调用了。

7.new

类方法new,定义在NSObject类中,

  • (instancetype)new OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
    new方法被认为是alloc和init方法的组合。源码如下:
+ (id)new {
    return [callAlloc(self, false/*checkNil*/) init];
}

其实就是把alloc和init结合起来了,不过现在init什么事都不做,如果没有重写init方法的话,new和alloc方法其实是一个意思了。但是,重写了init方法,new和alloc就不一样了。

我们在实验init方法的时候,重写了init方法,现在我们使用new再创建一个对象看看。


说一说基类 NSObject(二)_第9张图片
image.png

打印结果:


说一说基类 NSObject(二)_第10张图片
image.png

此时,我们发现,使用new创建的对象,执行了重写的init方法,这与只是用alloc创建的对象是不一样的。

你可能感兴趣的:(说一说基类 NSObject(二))