首先,我们都知道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类的更多相关文章

  1. 福利->KVC+Runtime获取类/对象的属性/成员变量/方法/协议并实现字典转模型

    我们知道,KVC+Runtime可以做非常多的事情.有了这个,我们可以实现很多的效果. 这里来个福利,利用KVC+Runtime获取类/对象的所有成员变量.属性.方法及协议: 并利用它来实现字典转模型 ...

  2. Runtime获取类的属性列表和方法列表

    Runtime获取类的属性列表和方法列表 Runtime很强大,他使得OC中没有真正意义上的私有属性和私有方法,我们可以利用OC的运行时拿到一个类的任何方法和任何属性,然后动态的去调用方法,objc_ ...

  3. NSObject类的API介绍

    这篇文章围绕的对象就是NSObject.h文件,对声明文件中的属性.方法进行必要的“翻译”. 该文件大致由两部分组成:NSObject协议和NSObject类. (一)NSObject协议 - (BO ...

  4. 利用NSUserdefaults来存储自定义的NSObject类及自定义类数组

    利用NSUserdefaults来存储自定义的NSObject类及自定义类数组 1.利用NSUserdefaults来存储自定义的NSObject类 利用NSUserdefaults也可以来存储及获取 ...

  5. 使用runtime给类动态添加方法并调用 - class_addMethod

    上手开发 iOS 一段时间后,我发现并不能只着眼于完成需求,利用闲暇之余多研究其他的开发技巧,才能在有限时间内提升自己水平.当然,“其他开发技巧”这个命题对于任何一个开发领域都感觉不找边际,而对于我来 ...

  6. RunTime 给类添加属性

    RunTime网上有很多人都不知道Runtime到底是干嘛的?有很多博主都是长篇大论给他们讲这个讲那个,我感觉还不如实例来的实在.很简单的一个例子:我们都知道会有这样的需求,未读消息列表的图片上要有一 ...

  7. Runtime单例模式类 -- 控制电脑关机

    package demo1; import java.io.IOException; public class RunTimeDemo { public static void main(String ...

  8. IOS SEL (@selector) 原理及使用总结(二)

    SEL消息机制工作原理是什么 引用下面文章: 我们在之前有提到,一个类就像一个 C 结构.NSObject 声明了一个成员变量: isa. 由于 NSObject 是所有类的根类,所以所有的对象都会有 ...

  9. Objective-C Runtime 运行时之一:类与对象

    Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一 ...

随机推荐

  1. UTF-8和GBK编码转换iconv

    iconv("GBK", "UTF-8", $str);//将GBK编码转换成UTF8编码

  2. Angular进阶教程三

    7 总结 angular上手比较难,初学者(特别是习惯了使用JQuery的人)可能不太适应其语法以及思想.随着对ng探索的一步步深入,也确实感觉到了这一点,尤其是框架内部的某些执行机制. 7.1页面效 ...

  3. SP从32位系统到64位系统的迁移方法

    前提:目标系统为64位1.在32位系统下正常安装SP,获取SP运行时必须的文件2.将[浪潮集团金融事业部]目录拷贝到目标系统的[C:\Program Files]目录3.进入目标系统的[浪潮集团金融事 ...

  4. Python爬虫教程-11-proxy代理IP,隐藏地址(猫眼电影)

    Python爬虫教程-11-proxy代理IP,隐藏地址(猫眼电影) ProxyHandler处理(代理服务器),使用代理IP,是爬虫的常用手段,通常使用UserAgent 伪装浏览器爬取仍然可能被网 ...

  5. QTreeView/QTableView中利用QStandardItem实现复选框三种形态变化

    https://www.techieliang.com/2017/12/729/ 原文地址 using_checkbox_item.h /** * @file using_checkbox_item. ...

  6. prince2的市场使用规模有多大?

    PRINCE2的使用和应用非常广泛.在过去的12个月里,超过60,000人参加了PRINCE2基础资格(Foundation)或从业资格(Practitioner)考试.现在每周参加考试的人数超过了2 ...

  7. linux 下的python的最佳打开方式, you know?

    IPython install IPython是Python的交互式Shell,提供了代码自动补完,自动缩进,高亮显示,执行Shell命令等非常有用的特性.特别是它的代码补完功能,例如:在输入zlib ...

  8. 三年Linux运维工作总结教训

    Linux运维一定要知道的六类好习惯和23个教训,避免入坑! 从事运维三年半,遇到过各式各样的问题,数据丢失,网站挂马,误删数据库文件,黑客攻击等各类问题. 今天简单整理一下,分享给各位小伙伴. 一. ...

  9. 【Oracle】等待事件详细内容

    一.等待事件的相关知识 1.1 等待事件主要可以分为两类,即空闲(IDLE)等待事件和非空闲(NON-IDLE)等待事件.1). 空闲等待事件指ORACLE正等待某种工作,在诊断和优化数据库的时候,不 ...

  10. HTML5离线存储之webstorage

    html5在引入webStorage之前,主要用cookies. html5的webstorage 分两种:LocalStorage 和SessionStorage,两者的差别主要在生命周期不同. 1 ...