说一说基类|说一说基类 NSObject(二)

本节我们继续学习NSObject,这个类中的很多方法都是我们常用的,所以要重点学习,花点时间也是值得的。
一、实例对象的生成和释放相关方法 1. alloc 类方法alloc,声明在NSObject类中。
+(instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
作用是生成消息接收类的实例对象,为实例对象开辟存储空间, 并初始化对象。之前alloc负责分配内存空间,init负责对对象进行初始化操作。通过实验我们知道,现在alloc方法就可以完成开辟空间和初始化的操作。
实际上,现在的alloc和new方法是一个意思了。 【说一说基类|说一说基类 NSObject(二)】验证之前,我们先新建一个target,新建一个类ClassA,如下图:

说一说基类|说一说基类 NSObject(二)
文章图片
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];

打印结果:

说一说基类|说一说基类 NSObject(二)
文章图片
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(二)
文章图片
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(二)
文章图片
image.png 3. release、retain、autorelease、retainCount 这几个方法都是关于内存管理的,手动内存管理(MRC)的时候用于增加引用计数,减少引用计数,返回引用计数。ARC中,这几个方法不可用。简单了解下。
这几个方法都是声明在NSObject协议中的。

说一说基类|说一说基类 NSObject(二)
文章图片
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进行内存管理。我们这里不再仔细深究。

说一说基类|说一说基类 NSObject(二)
文章图片
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(二)
文章图片
image.png 从打印结果可以看出,此时,只用alloc创建的对象和使用init初始化的对象是不一样的,只用alloc创建的对象不会走重写的init方法。
6.initialize方法
类方法initialize,定义在NSObject类中。
+(void)initialize;
这个方法用于类的初始化。这个方法会在类收到第一个消息之前被自动执行。
我们在ClassA的实现方法中,重写这个方法。
+ (void)initialize { if (self == [ClassA class]) { NSLog(@"ClassA 被初始化了"); } }

执行结果:

说一说基类|说一说基类 NSObject(二)
文章图片
image.png 我们发现,这个方法是最先执行的。
之前认为,这个方法不可以手动调用的,实验发现,是可以被手动调用的。

说一说基类|说一说基类 NSObject(二)
文章图片
image.png 看看打印:

说一说基类|说一说基类 NSObject(二)
文章图片
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(二)
文章图片
image.png 打印结果:

说一说基类|说一说基类 NSObject(二)
文章图片
image.png 此时,我们发现,使用new创建的对象,执行了重写的init方法,这与只是用alloc创建的对象是不一样的。

    推荐阅读