NSObject中的isa到底是个什么?

时间:2022-09-05 07:39:38

首先看一下NSObject的定义:

@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}

官方解释:Every object has an isa instance variable that identifies the object's class. The runtime uses this pointer to determine the actual class of the object when it needs to.

Every object is connected to the run-time system through its isa instance variable, inherited from the NSObject class. isa identifies the object's class; it points to a structure that's compiled from the class definition. Through isa, an object can find whatever information it needs at run timesuch as its place in the inheritance hierarchy, the size and structure of its instance variables, and the location of the method implementations it can perform in response to messages.

isa是一个Class, 那什么是Class? Class的定义:

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

哦, 是个结构体指针,objc_class是什么?

struct objc_class {
Class isa OBJC_ISA_AVAILABILITY; #if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif } OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

关键问题来了,objc_class里面也有一个Class isa,额,这是什么?下面我尽可能的简单的把事情说清楚。

1)首先很清楚这两个isa指向的不是同一个结构体:

2)究竟他们各自指向的是什么?先来看看第一个

@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}

这个isa指向的是class object,就是咱们经常说的类对象。不知道大家有没有印象,咱们经常会在一个类方法里面注册一个通知让这个“类”来监听一个某个事件,比如:

+ (void)registerEnterpriseVersionUpgrade
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkEnterpriseVersionAndTrigerUpgrade) name:UIApplicationWillEnterForegroundNotification object:nil];
}

这个类其实就是类对象,问题来了,这个“类”我没有创建过,它怎么会接收消息?是的,你没有创建过,但编译器帮你创建了,The class object is the compiled version of the class,而且是个单例。现在理解为什么一个“类”可以接收消息(类方法)了吧,因为他是一个被实例化的对象(后面会说到)。

这个类对象存储了struct objc_class里面的所有信息,方法名、属性、遵守的协议等等,额,等等,有个问题,方法名包括类方法和实例方法吗?等等,咱们看下实例化对象是怎么创建的。

当我们创建一个实例对象时,会这么操作:EnterpriseVersion *enterPriseVersion = [EnterpriseVersion new],咦,这是谁在接受alloc这个消息?想必你已经猜到了,就是我们前面说到的单例-类对象,类对象接收到new消息后(等会再说这个类对象是怎么知道可以接收这个消息的),根据自己存储的信息,创建了一个由enterPriseVersion指针指向的一个实例(NSObject)。每个实例都是继承自NSObject,自然也都有一个isa指针,这个isa指针都是指向这个单例,下面两个Class:aClass和bClass是一样的。

id aClass = [enterPriseVersion class];
id bClass = [EnterpriseVersion class];

创建完一个实例化对象enterPriseVersion之后,后面我们要做的就是向这个对象发送消息,比如我们向enterPriseVersion发送NSObject的一个实例化消息[enterPriseVersion copy],EnterpriseVersion并没有重写copy这个方法,它是如何找到父类(NSObject)的这个方法的呢?是这样的:

实例enterPriseVersion通过变量isa找到自己的类对象[EnterpriseVersion class](单例),前面说过,这个单例存储了实例的方法名、属性,遵守的协议等,单例查找到自己的方法列表是否有这个方法,如果有,则调用这个方法;如果没有,会根据保存的变量

Class super_class

找到父类对象[NSObject class](当然这也是个单例),然后在方法列表查找copy方法,找到后执行此消息,没有找到的话会进入异常处理(可以参考一些消息转发机制的文章)。

好了,到了这里实例化方法的调用很清楚了;那类方法的调用呢?这样聊到第二个isa了。

struct objc_class {
Class isa OBJC_ISA_AVAILABILITY; #if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif } OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

如同NSObject实例时通过isa指向的类对象(class object)创建的一样,类对象的也是通过自己的isa指向的元类(metaclass object)创建的,换句话说,类对象是元对象的实例!!!元类对象和类对象不同结构虽然相同,但存储的信息不同,元对象存储的是类对象的信息,如版本,名字,类方法等,而类对象存储的实例对象的信息,如变量名、实例方法等。

先来说说类方法是如何调用的,当执行了[EnterpriseVersion new]方法时,这个时候类对象收到个new消息(类方法)后,通过类对象的isa找到metaclass object(单例哦),在类方法列表查找是否有new方法,如果有,执行;如果没有,通过

Class super_class

查找到父metaclass object,同样在类方法列表查找new类方法,没有找到,继续通过父mataclass object的isa向上遍历...这样,类方法和类对象应该清楚了。

可问题来了,按照我们之前的逻辑metaclass object是个某个类的实例,它是谁创建的呢?这样类似的问题,算这次,问了3次了,不想再问了,也不想写了,可好消息是,这就结束了。

metaclass object是metaclass的实例,mataclass的通过super_class查找super metaclass,直到root metaclass,root metaclass的super_class指向自己。

总结一下:

instance object 的isa->class object, class object 的isa->metaclass object, metaclass object 的isa指root metaclass object(NSObject object), rootmetaclass object的isa指向自身;

注意:instance object只有isa这一个成员变量,没有super_class的哦...别混了, 查找super_class的是instance object的isa指向的class obcjet。

class_object的super_class->class_object的super class,然后继续super super class...  直到root class(NSOjbect class),root class 的super_class指向nil。

是不是清楚isa是什么了?下面来看一个具体的问题:

Objective-C的运行时动态特性决定了某个对象在生命周期内,其isa指向的类对象是可能改变的,也就是isa指针指向的对象有可能改变,Apple把这种技术叫做isa-swizzling。举个例子,当对某个对象使用了KVO之后,Objective-C实际上是动态的创建了另一个类对象,并把将isa指向这个实例。这时候该对象的isa指针就很不幸的被改变了。实际上,isa指针是Objective-C运行时系统使用到的一个变量,我们在程序中应该尽量不要依赖它。apple有云:

When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class. As a result the value of the isa pointer does not necessarily reflect the actual class of the instance. Instead of relying on the isa pointer your application should use the class method to determine the class of an object instance.

参考资料:

1)https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/ObjectAllocation/ObjectAllocation.html#//apple_ref/doc/uid/TP40010810-CH7-SW1

2)http://www.cocoadev.cn/CocoaDev/Key-Value-Observing-Quick-Start-cn.asp

3)https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010810-CH1-SW1

4)http://blog.csdn.net/tskyfree/article/details/7984887

NSObject中的isa到底是个什么?的更多相关文章

  1. Python类中的self到底是干啥的

    Python类中的self到底是干啥的 Python编写类的时候,每个函数参数第一个参数都是self,一开始我不管它到底是干嘛的,只知道必须要写上.后来对Python渐渐熟悉了一点,再回头看self的 ...

  2. 有趣的冷知识:编程中Foo&comma; Bar 到底什么意思?

    转自:编程中Foo, Bar 到底什么意思? 1 前言 在很多国外计算机书本和一些第三份开源软件的Demo中经常用到两个英文单词Foo,Bar.这到底是什么意思呢?从步入屌丝界的IT生活见到这两个单词 ...

  3. 【Java面试题】15 String s&equals;&quot&semi;Hello&quot&semi;&semi; s&equals;s&plus;&OpenCurlyDoubleQuote;world!”&semi;这两行代码执行后,原始的String对象中的内容到底变了没有?String与StringBuffer的超详细讲解!!!!!

    1.Java中哪些类是不能被继承的? 不能被继承的是那些用final关键字修饰的类.一般比较基本的类型或防止扩展类无意间破坏原来方法的实现的类型都应该是final的,在java中,System,Str ...

  4. NSObject 中执行Selector 的相关方法

    1. 对当前Run Loop中Selector Sources的取消 NSObject中的performSelector:withObject:afterDelay:方法将会在当前线程的Run Loo ...

  5. iOS&colon; NSObject中执行Selector的相关方法

    本文转载至 http://www.mgenware.com/blog/?p=463 1. 对当前Run Loop中Selector Sources的取消 NSObject中的performSelect ...

  6. python中的cls到底指的是什么

    python中的cls到底指的是什么,与self有什么区别? 2018年07月31日 11:13:09 rs勿忘初心 阅读数:7769   作者:秦风链接:https://www.zhihu.com/ ...

  7. linux中的selinux到底是什么

    一文彻底明白linux中的selinux到底是什么 2018年06月29日 14:17:30 yanjun821126 阅读数 58877 标签: SElinux 更多 个人分类: Linux   一 ...

  8. Django中的request到底有啥属性

    Django中的request到底有啥属性呢 Request 我们知道当URLconf文件匹配到用户输入的路径后,会调用对应的view函数,并将  HttpRequest对象  作为第一个参数传入该函 ...

  9. Java中的String到底占用多大的内存空间?你所了解的可能都是错误的!!

    写在前面 最近小伙伴加群时,我总是问一个问题:Java中的String类占用多大的内存空间?很多小伙伴的回答着实让我哭笑不得,有说不占空间的,有说1个字节的,有说2个字节的,有说3个字节的,有说不知道 ...

随机推荐

  1. linux重定向

    常用FD有3个,为0(stdin,标准输入).1(stdout,标准输出).2(stderr,标准错误输出),默认与keyboard.monitor有关: cmd > file 把 stdout ...

  2. &lbrack;原创&rsqb;Win7、Win8、Win10始终以管理员身份运行程序。

    在Win7.Win8.Win10系统中,以管理员身份运行程序很麻烦,一般有以下几种方式: 1.在可执行程序或快捷方式上右键,以管理员身份运行: 2.在可执行程序或快捷方式上右键->属性-> ...

  3. 由一个activity跳转到另一个activity

    定义一个按钮,当点击的时候跳转到另一个activity的界面 1.新建第二个activity 2.在第二个Java源码处继承第一个activity,导入 3.在source中复写Oncreat方法 4 ...

  4. DOM中事件绑定补充方法

    先将上一篇文章中提到的为元素增加事件的方法和移除事件的方法拿过来: <span style="font-size:18px;">//跨浏览器添加事件 function ...

  5. Android Training精要&lpar;四&rpar; Intent注意事项

    判断有处理Intent的Activity PackageManager packageManager = getPackageManager(); List<ResolveInfo> ac ...

  6. x264 编码器选项分析 &lpar;x264 Codec Strong and Weak Points&rpar; 1

    文章文件夹: x264 编码器选项分析 (x264 Codec Strong and Weak Points) 1 x264 编码器选项分析 (x264 Codec Strong and Weak P ...

  7. (转)苹果iOS开发者账号过期临时解决方法

    苹果iOS开发者账号过期临时解决办法 苹果iOS开发者账号一年的费用是99美金,作者最近由于各种原因,导致renew没能在账号过期之前支付好,所以在账号过期等待renew的期间,试了试一些非正常手段, ...

  8. MySql数据库的基本原理及指令

    1.什么是数据库 数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储起来,用户可以通过SQL对数据库中的数据进行增加,修改,删除及查询操作. 2.简介 MySQL是一个开放源 ...

  9. 【转载】MapReduce编程 Intellij Idea配置MapReduce编程环境

    目录(?)[-] 一软件环境 二创建maven工程 三添加maven依赖 四配置log4j 五启动Hadoop 六运行WordCount从本地读取文件 七运行WordCount从HDFS读取文件 八代 ...

  10. jquery 无缝轮播

    新闻公告无缝轮播--demo 理解:向上移动一个li的高度+margin-bottom值,同时将ul第一个的li插入到ul的最后一个位置. <!DOCTYPE html> <html ...