Runtime - ② - NSObject类
首先,我们都知道NSObject是大多数类的根类,但是,这个类的是怎么实现的呢?我们可以去下载开源的Runtime源码,探究下NSObject类的实现。
1. NSObject.h文件
我们可以直接使用Command点NSOject进去看到它的头文件,可以看到,NSObject.h文件中有两块内容:
- NSObject 协议
- NSObject 实现
1.1 NSObject 协议
@protocol NSObject
- (BOOL)isEqual:(id)object;
@property (readonly) NSUInteger hash;
@property (readonly) Class superclass;
- (Class)class OBJC_SWIFT_UNAVAILABLE("use 'type(of: anObject)' instead");
- (instancetype)self;
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
- (BOOL)isKindOfClass:(Class)aClass;
- (BOOL)isMemberOfClass:(Class)aClass;
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;
@end
这里只是粘贴了部分方法,其中也有很多我们熟悉的方法,比如判断代理是否实现某个方法,实现某个协议等等,这个也就解释了,为什么我们自定义的协议也要遵循NSObject的协议,我们可以直接使用NSObject协议中的方法,去判断代理是否实现了,因为协议有Optional这个关键字,协议的方法是可选实现的。
1.2 NSObject的成员变量
我们还是在NSObject.h文件中,可以看到,NSObject只有一个成员变量是Class类型的isa变量:
@interface Object
{
Class isa; /* A pointer to the instance's class structure */
}
那么Class类型是什么类型呢?我们可以大概的猜想一下,可能就是指它所属的类吧。
Now,我们Command继续看这个Class的实现。
1.3 Class是什么玩意?
typedef struct objc_class *Class;
简单明了,Class就是一个指向结构体的指针。关于这一块,不明白结构体指针的,还需要去补充一下这方面的知识。然后,我们继续看 objc_class 这个结构体:
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY; // 还是那个指针 #if !__OBJC2__
Class _Nullable super_class // 父类 OBJC2_UNAVAILABLE;
const char * _Nonnull name // 类名 OBJC2_UNAVAILABLE;
long version // 版本 OBJC2_UNAVAILABLE;
long info // 包含信息 OBJC2_UNAVAILABLE;
long instance_size // 成员变量的size? OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars // 成员变量存储list OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists // 类中的方法 OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache // 类中的方法缓存 OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols // 类中的协议列表 OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
我们这里先看下isa指针:
- isa:在这个结构体中我们看到也有一个isa指针,这个isa指针指向的是meta class,这里补充一下,类其实也是一个对象就是类对象。
搞到这里有点晕了,我们可以看下id类型是个啥类型,可以对比一下。
1.4 id类型
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
}; /// A pointer to an instance of a class.
typedef struct objc_object *id;
我们可以发现,id类型其实也是一个结构体指针啊,这里我们可以看到,objc_object 这个结构体中也有一个 isa变量。So,我们在NSObject,objc_class,objc_object中看到都有一个objc_class *类型,也就是Class类型的变量isa,可见这个isa是多么的重要啊。
我们可以得到大概这样的结论,在objc的runtime中,类是用objc_class结构体表示的,对象是用objc_object结构体表示的,对象的isa用来标示这个对象是哪一个类的实例。我们可以通过几个方法来验证一下。
2. NSObject.m
我们经常使用的判断一个对象是不是某个类或这个类的派生类的实例,那么我们就去看一下这两个方法的实现
- (Class)class {
return object_getClass(self);
} Class object_getClass(id obj){
if (obj) return obj->getIsa();
else return Nil;
} - (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
上面的三个方法简单明了,我们在判断一个对象是否是某个类的实例时,其实就是看这个对象中的isa指针是否指向某个类,当我们调用self class方法时,其实也就是拿到这个实例对象的isa指针,也就是指向结构体objc_class的指针,然后进行判断返回结果。所以,我们可以知道,对于某个普通的对象实例,通过调用[object class]其实返回的就是这个实例的isa变量。
一个类的实例对象的isa指针指向的是这个对象所属的类,这个类描述了一系列它的实例的特点,就像上面的objc_class结构体中的成员变量列表,成员函数的列表等。这个对象能够接受的消息列表也是存储在这个类中。
下面我们也分析一下objc_class,为什么也有一个isa变量呢?
在面向对象的世界中,万物皆对象,所以,类也是一个对象:类对象。它也有一个isa指针,那么它指向谁呢?我们可以看下 +Class方法的实现:
+ (Class)class {
return self;
}
为什么返回的竟然是self呢?我们知道对于某个类的实例来说,self总是指向其自身的,但是这里并没有实例啊,我们是直接调用了这个类的类方法啊,难道类本身也有一个self指针?这个方法的返回值是一个类对象,所以其本质还是一个对象。对于NSObject这样的类来说,它其实也就代表一个类对象,类对象的self指针应该指向的也是这个类对象自身。
Runtime - ② - NSObject类的更多相关文章
- 福利->KVC+Runtime获取类/对象的属性/成员变量/方法/协议并实现字典转模型
我们知道,KVC+Runtime可以做非常多的事情.有了这个,我们可以实现很多的效果. 这里来个福利,利用KVC+Runtime获取类/对象的所有成员变量.属性.方法及协议: 并利用它来实现字典转模型 ...
- Runtime获取类的属性列表和方法列表
Runtime获取类的属性列表和方法列表 Runtime很强大,他使得OC中没有真正意义上的私有属性和私有方法,我们可以利用OC的运行时拿到一个类的任何方法和任何属性,然后动态的去调用方法,objc_ ...
- NSObject类的API介绍
这篇文章围绕的对象就是NSObject.h文件,对声明文件中的属性.方法进行必要的“翻译”. 该文件大致由两部分组成:NSObject协议和NSObject类. (一)NSObject协议 - (BO ...
- 利用NSUserdefaults来存储自定义的NSObject类及自定义类数组
利用NSUserdefaults来存储自定义的NSObject类及自定义类数组 1.利用NSUserdefaults来存储自定义的NSObject类 利用NSUserdefaults也可以来存储及获取 ...
- 使用runtime给类动态添加方法并调用 - class_addMethod
上手开发 iOS 一段时间后,我发现并不能只着眼于完成需求,利用闲暇之余多研究其他的开发技巧,才能在有限时间内提升自己水平.当然,“其他开发技巧”这个命题对于任何一个开发领域都感觉不找边际,而对于我来 ...
- RunTime 给类添加属性
RunTime网上有很多人都不知道Runtime到底是干嘛的?有很多博主都是长篇大论给他们讲这个讲那个,我感觉还不如实例来的实在.很简单的一个例子:我们都知道会有这样的需求,未读消息列表的图片上要有一 ...
- Runtime单例模式类 -- 控制电脑关机
package demo1; import java.io.IOException; public class RunTimeDemo { public static void main(String ...
- IOS SEL (@selector) 原理及使用总结(二)
SEL消息机制工作原理是什么 引用下面文章: 我们在之前有提到,一个类就像一个 C 结构.NSObject 声明了一个成员变量: isa. 由于 NSObject 是所有类的根类,所以所有的对象都会有 ...
- Objective-C Runtime 运行时之一:类与对象
Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一 ...
随机推荐
- sql With(NoLock),With(ReadPast)
--------------- create table tmp1 ( id int primary key, name ) ) ----------- insert into tmp1(id,nam ...
- <Android 基础(二十三)> Android Studio快捷键
前言 Android Studio对于快捷键的设置比较的灵活,开发者在从不同的平台转移到Android Studio进行Android开发的时候,应该都能找到合适的KeyMap和快捷键使用方式,因为A ...
- 【vue】混合模式
因为工作的分配,写财务的对账部分,因为3个页面的设计和功能基本相同,都是查询筛选表格,所以用混合模式优化了部分代码.用混合把一些共用的东西抽离了出来. 具体使用方法参照文档. https://cn.v ...
- MPU/SoC/Application Processor/Embedded OS
Everything has its principles and mechanisms which are designed by its creator and followed by its u ...
- grep用法详解:grep与正则表达式
首先要记住的是: 正则表达式与通配符不一样,它们表示的含义并不相同!正则表达式只是一种表示法,只要工具支持这种表示法, 那么该工具就可以处理正则表达式的字符串.vim.grep.awk .sed 都支 ...
- MySQL事务管理
事务就是一组原子性的SQL查询,或者说一个独立的工作单元.如果数据库引擎能够成功地对数据库应用该组查询的全部语句,那么就执行该组的全部语句,如果其中有任何一条语句因为崩溃或者其他原因无法执行,那么所有 ...
- Androidpdf
https://www.jb51.net/article/110238.htm https://blog.csdn.net/u010046908/article/details/53927157 &l ...
- Apache的主要目录和配置文件详解
一.Apache 主要配置文件注释Apache的主配置文件:/etc/httpd/conf/httpd.conf默认站点主目录:/var/www/html/Apache服务器的配置信息全部存储在主配置 ...
- 常见网络编程面试题答案征集与面试题(收集) ZZ 【网络编程】
http://www.cnblogs.com/wickedboy237/archive/2013/05/12/3074362.html 1:tcp和udp的区别2:流量控制和拥塞控制的实现机制3:滑动 ...
- [翻译] KGModal
KGModal KGModal is an easy drop in control that allows you to display any view in a modal popup. The ...