NSObject中的isa到底是个什么?

首先看一下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

posted on 2015-04-21 11:27  goodyboy6  阅读(358)  评论(0)    收藏  举报

导航