说一说基类 NSObject(一)
OC是一门动态语言,运行时系统实现了OC的动态性。运行时系统提供了很多方法,但是我们不能直接使用,我们常用的运行时系统的功能定义在了根类NSObject中。也就是说,根类方法中提供了运行时系统的基本功能,根类相当于运行时系统的一个接口
。
- 关于类对象的说明:
面向对象的语言中对类有两种认识,一种是认为类只是作为类型的定义,程序运行时不作为实体存在;另外一种是认为类本身也是作为一个对象存在。我们把后一种定义中类的对象叫做类对象
。
这种情况下类定义就分为两部分,一部分定义所生成的实例的类型,另一部分则定义类自身的行为。OC把类作为对象看待,而在C++中,类只被作为类型的定义使用。
类对象有自己的方法和变量,分别被称为类方法
和类变量
。
在OC中,只有类方法的概念,没有类变量的概念。
OC中是如何实现“类变量”的呢?
OC中通过实现文件中定义静态变量
的方法来代替类变量。
类对象是程序执行过程中自动生成的,每个类只有一个类对象,不需要手动生成。
- 关于Class的说明:
类对象也是有类型的,OC中专门定义了一个Class类型用来表示类对象,所有类对象都是Class类型。所以,我们看到NSObject中很多返回类对象的方法的返回值都是Class类型。比如:
+(Class)superclass;
+(Class)class;
-(Class)class;
一、关于isa
NSObject只有一个实例变量,就是Class类型的变量isa,isa用于标识实例对象属于哪个类对象。因为isa决定着实例变量和类的关系,非常重要,所以子类不可以修改isa的值。另外也不能通过直接访问isa来查询实例变量到底属于哪个类,而要通过实例方法class来完成。
二、NSObject的几个常用方法
下面我们就来看看NSObject的常用方法吧。
为了验证这些方法,我们需要一个测试程序。
image.png
ObjectTest.h
// Copyright © 2020 weiman. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface ObjectTest : NSObject
@property(nonatomic, copy)NSString * name;
-(id)initWithName:(NSString *)name;
@end
NS_ASSUME_NONNULL_END
ObjectTest.m
// Copyright © 2020 weiman. All rights reserved.
//
#import "ObjectTest.h"
@implementation ObjectTest
-(id)initWithName:(NSString *)name {
if (self = [super init]) {
self.name = name;
}
return self;
}
@end
重点来了
我们先打开NSObject.h文件看一看,大致浏览下。
我们看到NSObject.h文件大致有两部分组成,一部分是NSObject协议,一个是NSObject类,NSObject类遵守了NSObject协议,那肯定也会实现该协议中定义的方法,只是我们在声明文件中看不到了。
点开NSObject类:
image.png
在main文件中的main方法中进行测试。
先定义两个对象,一个是NSObject类型的,一个是ObjectTest类型的。
NSObject * obj = [[NSObject alloc] init];
ObjectTest * test = [[ObjectTest alloc] initWithName:@"小米粒"];
1.对象方法class
-(Class)class OBJC_SWIFT_UNAVAILABLE("use 'type(of: anObject)' instead");
说明:
OBJC_SWIFT_UNAVAILABLE("use 'type(of: anObject)' instead");的意思是在swift中使用type(of: anObject)来代替class 方法。这是题外话,不用在意。
对象方法class定义在protocol NSObject中,NSObject类遵守了
这个协议,也就在NSObject的实现文件中实现了这个方法。
对象方法class返回对象所属的类的类对象。
测试代码:
NSLog(@"-------------对象方法class-----------------");
NSLog(@"obj class, %@",[obj class]);
NSLog(@"test class, %@",[test class]);
printf("\n");
打印结果:
image.png
2.类方法class
+(Class)class OBJC_SWIFT_UNAVAILABLE("use 'aClass.self' instead");
类方法class,定义在NSObject类中,是NSObject类的一个公有方 法,返回类对象。
测试程序:
NSLog(@"-------------类方法class-----------------");
NSLog(@"NSObject class, %@", [NSObject class]);
NSLog(@"ObjectTest class, %@", [ObjectTest class]);
printf("\n");
打印结果:
image.png
3.对象方法self,也是定义在NSObject协议中的,声明为:
- (instancetype)self;
此方法返回对象自身,是一个无任何实际动作,但是很有用的方法。
测试程序:
NSLog(@"-------------对象方法self-----------------");
NSLog(@"obj self, %@",[obj self]);
NSLog(@"test self, %@",[test self]);
NSLog(@"test self, %@",[test self].name);
printf("\n");
打印结果:
image.png
4.对象方法isMemberOfClass也是定义在协议中的一个方法,声明为:
- (BOOL)isMemberOfClass:(Class)aClass;
用于判断对象是不是参数aClass类的对象。
注意:这个方法判断的时候,如果参数是父类,则返回NO。
测试程序:
BOOL isTest = [test isMemberOfClass:[NSObject class]];
BOOL isTest2 = [test isMemberOfClass:[ObjectTest class]];
BOOL isTest3 = [obj isMemberOfClass:[ObjectTest class]];
BOOL isTest4 = [obj isMemberOfClass:[NSObject class]];
NSLog(@"-------------isMemberOfClass--------------");
NSLog(@"test 是不是 NSObject 类型?%@", isTest ? @"是" : @"否");
NSLog(@"test 是不是 ObjectTest 类型?%@", isTest2 ? @"是" : @"否");
NSLog(@"obj 是不是 ObjectTest 类型?%@", isTest3 ? @"是" : @"否");
NSLog(@"obj 是不是 NSObject 类型?%@", isTest4 ? @"是" : @"否");
printf("\n");
打印结果:
image.png
5.对象方法isKindOfClass也是定义在协议中的,声明为:
- (BOOL)isKindOfClass:(Class)aClass;
作用于isMemberOfClass类似,但是也有不同。这个方法的作用是判断消息接受者是否是参数aClass类或者aClass的父类的实例。
测试程序:
BOOL isTestKind = [test isKindOfClass:[NSObject class]];
BOOL isTestKind2 = [test isKindOfClass:[ObjectTest class]];
BOOL isTestKind3 = [obj isKindOfClass:[ObjectTest class]];
BOOL isTestKind4 = [obj isKindOfClass:[NSObject class]];
NSLog(@"-------------isKindOfClass--------------");
NSLog(@"test 是不是 NSObject 类型?%@", isTestKind ? @"是" : @"否");
NSLog(@"test 是不是 ObjectTest 类型?%@", isTestKind2 ? @"是" : @"否");
NSLog(@"obj 是不是 ObjectTest 类型?%@", isTestKind3 ? @"是" : @"否");
NSLog(@"obj 是不是 NSObject 类型?%@", isTestKind4 ? @"是" : @"否");
printf("\n");
打印结果:
image.png
6.类方法isSubclassOfClass定义在NSObject类的一个公有方法, 声明为:
+(BOOL)isSubclassOfClass:(Class)aClass;
判断消息接收者是不是参数aClass的子类或者自身。
测试程序:
BOOL isTestsub = [NSObject isSubclassOfClass:[test class]];
BOOL isTestsub2 = [ObjectTest isSubclassOfClass:[test class]];
BOOL isTestsub3 = [NSObject isSubclassOfClass:[obj class]];
BOOL isTestsub4 = [ObjectTest isSubclassOfClass:[obj class]];
BOOL isTestsub5 = [ObjectTest isSubclassOfClass:[NSObject class]];
NSLog(@"-------------isSubclassOfClass-----------");
NSLog(@"NSObject 是不是 test所属类 的子类或自身?%@", isTestsub ? @"是" : @"否");
NSLog(@"ObjectTest 是不是 test所属类 的子类或自身?%@", isTestsub2 ? @"是" : @"否");
NSLog(@"NSObject 是不是 obj所属类 子类或自身?%@", isTestsub3 ? @"是" : @"否");
NSLog(@"ObjectTest 是不是 obj所属类 子类或自身?%@", isTestsub4 ? @"是" : @"否");
NSLog(@"ObjectTest 是不是 NSObject 子类或自身?%@", isTestsub5 ? @"是" : @"否");
printf("\n");
打印结果:
image.png
- superclass,定义在协议中,是一个只读的属性。
@property (readonly) Class superclass;
我们可以使用对象来调用superclass,就像一个对象方法一样,其实是调用它的getter方法。
superclass的作用是:返回对象所在类的父类。
为了更好的说明,我们再建一个新的类TestSon,继承自ObjectTest。
image.png
TestSon.h
#import "ObjectTest.h"
NS_ASSUME_NONNULL_BEGIN
@interface TestSon : ObjectTest
-(void)sayHi;
@end
TestSon.m
#import "TestSon.h"
@implementation TestSon
-(void)sayHi {
NSLog(@"Hi, I am son class");
}
@end
测试程序:
NSLog(@"-------------对象方法superclass-----------");
TestSon * son = [[TestSon alloc] initWithName:@"小苗苗🌹"];
NSLog(@"obj superclass:%@",[obj superclass]);
NSLog(@"test superclass:%@",[test superclass]);
NSLog(@"son superclass:%@",[son superclass]);
NSLog(@"son superclass:%@",son.superclass);
NSLog(@"son name%@",[son name]);
NSLog(@"son name%@",son.name);
printf("\n");
打印结果:
image.png
- 类方法superclass,定义在NSObject类中,返回类对象。
+ (Class)superclass;
测试程序:
NSLog(@"NSObject superclass:%@",[NSObject superclass]);
NSLog(@"ObjectTest superclass:%@",[ObjectTest superclass]);
NSLog(@"TestSon superclass:%@",[TestSon superclass]);
NSLog(@"NSString superclass:%@",[NSString superclass]);
NSLog(@"NSArray superclass:%@",[NSArray superclass]);
NSLog(@"NSMutableArray superclass:%@",[NSMutableArray superclass]);
打印结果:
image.png
本节内容回顾:
一、类对象的概念
OC中把类也作为一种对象看待,每个类有且只有一个类对象,程序运行过程中自动生成。
二、Class类型说明
所有类对象的类型是Class。
三、NSObject的几个常用方法
当然了,NSObject的常用方法还有很多,后面再一一学习,本节我们就学习了8个,分别是:
- -(Class)class;
返回对象的类对象。
2.+(Class)class;
返回类的类对象。
3.-(id)self;
返回对象自身实例。
4.-(BOOL)isMemberOfClass:(Class)aClass;
判断是否是参数类对象aClass的实例。不包含父类。
5.-(BOOL)isKindOfClass:(Class)aClass;
判断是否是参数类对象aClass的实例。包含父类。
6.-(BOOL)isSubclassOfClass:(Class)aClass;
判断是否是参数类对象aClass的子类或者自身。
7.-(Class)superclass;
返回实例对象所在类的父类。
8.+(Class)superclass;
返回类对象的父类。
祝大家生活愉快!