本节我们继续学习NSObject,这个类中的很多方法都是我们常用的,所以要重点学习,花点时间也是值得的。
一、实例对象的生成和释放相关方法
1. alloc
类方法alloc,声明在NSObject类中。
+(instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
作用是生成消息接收类的实例对象,为实例对象开辟存储空间, 并初始化对象。之前alloc负责分配内存空间,init负责对对象进行初始化操作。通过实验我们知道,现在alloc方法就可以完成开辟空间和初始化的操作。
实际上,现在的alloc和new方法是一个意思了。
验证之前,我们先新建一个target,新建一个类ClassA,如下图:
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];
打印结果:
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);
}
再次运行,看看打印结果
因为我们是把对象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;
}
看看打印结果:
3. release、retain、autorelease、retainCount
这几个方法都是关于内存管理的,手动内存管理(MRC)的时候用于增加引用计数,减少引用计数,返回引用计数。ARC中,这几个方法不可用。简单了解下。
这几个方法都是声明在NSObject协议中的。
-(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进行内存管理。我们这里不再仔细深究。
从截图上我们看到,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];
打印结果:
从打印结果可以看出,此时,只用alloc创建的对象和使用init初始化的对象是不一样的,只用alloc创建的对象不会走重写的init方法。
6.initialize方法
类方法initialize,定义在NSObject类中。
+(void)initialize;
这个方法用于类的初始化。这个方法会在类收到第一个消息之前被自动执行。
我们在ClassA的实现方法中,重写这个方法。
+ (void)initialize
{
if (self == [ClassA class]) {
NSLog(@"ClassA 被初始化了");
}
}
执行结果:
我们发现,这个方法是最先执行的。
之前认为,这个方法不可以手动调用的,实验发现,是可以被手动调用的。
看看打印:
也是被成功调用了。
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再创建一个对象看看。
打印结果:
此时,我们发现,使用new创建的对象,执行了重写的init方法,这与只是用alloc创建的对象是不一样的。