首先,我们都知道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. laravel开发之-网站初建

    1 cmd 打开电脑命令窗口 2 目录切换到网站根目录 3 输入命令:php artisan serve 4 model 生成命令:php artisan make:model 需要生成的model名 ...

  2. 然之协同系统6.4.1 SQL注入之exp编写

    前言 前面已经说明了 漏洞成因,这里介绍一下 exp 的编写. 正文 为了 getshell 或者是 任意文件下载, 我们需要修改 数据库中的 前缀sys_file 表, 所以我们的利用方式如下 使用 ...

  3. 网络测速 php代码

    <?php /*=====http://hi.csdn.net/yinyiniao=====*/ $fp=fopen("cs.txt","w"); for ...

  4. LeetCode 1. Two Sum (JavaScript)

    1. Two Sum Given an array of integers, return indices of the two numbers such that they add up to a ...

  5. HTML5新增的标签和属性归纳

    收集总结的HTML5的新特性,基本除了IE9以下都可以使用. HTML5语法 大部分延续了html的语法 不同之处:开头的 <!DOCTYPE html> <html lang=&q ...

  6. 《SQL必知必会》知识点汇总

    select CustomerNo from dbo.Customers; 通配符的使用 select *from dbo.Customers; select CustomerNo from dbo. ...

  7. Asp.Net MVC4 系列-- 进阶篇之路由

    原文  http://blog.csdn.net/lan_liang/article/details/22993839 创建一个路由 打开 RouteConfig.cs  ,发现已经创建了一个默认路由 ...

  8. Python初学者第十六天 文件处理操作练习

    16day 练习:模拟登陆 1.用户输入账号密码进行登陆: 2.用户信息保存在文件内: 3.用户密码输入错误三次后,锁定用户,下次登陆,检测到这个用户再也登陆不了 #获取用户名及密码f_user = ...

  9. July 27th 2017 Week 30th Thursday

    A smile is the most charming part of a person forever. 微笑永远是一个人身上最好看的东西. Smile in the mirror, and yo ...

  10. php性能调优

    第一章  针对系统调用过多的优化 我这次的优化针对syscall调用过多的问题,所以使用strace跟踪apache进行分析. 1.  apache2ctl -X & 使用-X(debug)参 ...