首先看一下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, Bar 到底什么意思?

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

  3. 【Java面试题】15 String s="Hello"; s=s+“world!”;这两行代码执行后,原始的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: 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系统镜像

    使用软件和平台 1.基于平台:                  Vmware workstation 8.0 2.基于系统镜像:               rhel-server-5.8-i386 ...

  2. [Swustoj 24] Max Area

    Max Area 题目描述: 又是这道题,请不要惊讶,也许你已经见过了,那就请你再来做一遍吧.这可是wolf最骄傲的题目哦.在笛卡尔坐标系正半轴(x>=0,y>=0)上有n个点,给出了这些 ...

  3. Objective-C 记录

    NSdata 与 NSString,Byte数组,UIImage 的相互转换 原文网址:http://www.cnblogs.com/jacktu/archive/2011/11/08/2241528 ...

  4. javascript二维数组

    var a= new Array(new Array(1,2),new Array('b','c')); document.write(a[1][1]); 说白了,就是利用for循环定义二维数组! & ...

  5. [转]ASP.NET MVC 入门8、ModelState与数据验证

    ViewData有一个ModelState的属性,这是一个类型为ModelStateDictionary的ModelState类型的字典集合.在进行数据验证的时候这个属性是比较有用的.在使用Html. ...

  6. [liu yanling]黑盒测试用例设计方法

    1. 概述 黑盒测试用例设计方法包括等价类划分法.边界值分析法.错误推测法.因果图法.判定表驱动法.正交试验设计法.功能图法等. 2. 等价类划分法 2.1.          概念 等价类划分法是把 ...

  7. .net软件自动化测试笔记(API-2)

    1.9获得测试运行时间如何获得测试运行的总时间设计:DateTime.Now属性记录测试开始运行时间,以及测试结束时间,用一个TimeSpan对象计算本次运行的总时间 DateTime starTim ...

  8. 基于Geoserver配置多图层地图以及利用uDig来进行样式配置

    在GeoServer中配置多个图层的地图相对来说很容易,其步骤为: 1. 进入geoserver 2. 配置相关的FeatureTypes 3. 配置WMS内容,进入以后,主要有以下几个地方需要命名: ...

  9. 四元数(Quaternion)详细讲解以及在图形图像编程中的使用

    关于四元数介绍可以直接看wiki,写的很详细了. 四元数的基本运算:http://www.linuxgraphics.cn/opengl/opengl_quaternion.html,代码有些问题. ...

  10. EGit插件安装(附Eclipse版本对应表)

    最近eclipse添加egit插件,通过网上的方法下载安装后不显示git选项.通过官网了解到egit的版本对应相应的eclipse版本. 如果你安装了最新版本,需要先卸载重启eclipse后重新安装兼 ...