您的位置:首页 > 移动开发 > IOS开发

ios isa 是什么鬼???

2016-05-18 14:40 543 查看
每个Objective-C对象都有一个隐藏的数据结构,这个数据结构是Objective-C对象的第一个成员变量,它就是isa指针。

这个isa到底是什么呢?官方介绍是这样的:

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

可见,一个对象(Object)的isa指向了这个对象的类(Class),而这个对象的类(Class)的isa指向了metaclass。这样我们就可以找到静态方法和变量了。
Objective-C的运行时是动态的,它能让你在运行时为类添加方法或者去除方法以及使用反射。这在其它语言是不多见的。

类的实例对象的 isa 指向它的类;类的 isa 指向该类的 metaclass;
类的 super_class 指向其父类,如果该类为根类则值为 NULL;
metaclass 的 isa 指向根 metaclass,如果该 metaclass 是根 metaclass则指向自身;
metaclass 的 super_class 指向父 metaclass,如果该 metaclass 是根 metaclass则指向该 metaclass 对应的类;

Object-C 为每个类的定义生成两个 objc_class ,一个普通的 class,另一个即metaclass。我们可以在运行期创建这两个 objc_class 数据结构,然后使用 objc_addClass将 class注册到运行时系统中,以此实现动态地创建一个新的类。

在NSObject.h里面:

@interface NSObject <NSObject> {
Class isa
OBJC_ISA_AVAILABILITY;
}
再点开 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
}
这一些定义对于懂的人自然懂,不会的人根本看不懂。建议看完下面的例子,再点开参考里面的链接仔细看一遍。

现在我们知道的是,对于我们新建的一个类,都会有一个隐藏的属性isa,可以通过它进行一些访问。

我们现在新建一个类Parent,继承于NSObject, 里面有成员方法-(void)selectorP,类方法+(void)ClassSelectorP。

再新建一个类Child,继承于Parent,里面有成员方法-(void)selectorC, 类方法+(void)ClassSelectorC。

现在我们新建一个实例Child* child = [Chlid new];

1,当我们调用[child class] 的时候,child就会通过isa指针去找到Child的class。

2,当我们调用[child superclass]的时候,child 通过isa找到Child的class,再通过super_class,找到Parent的class。

在这里,再普及objc_class 的两种类型:

class     实例对象(child、Child)的isa指向的结构体;

metaclass  class的isa指向的一个结构体;

3,接着,调用[child SelectorC],child通过isa找到Child的class,在class(注意看上面 struct objc_class 的定义)的方法列表里面找到SelectorC;

4,再试着调用[child SelectorP],child通过isa找到Child的class,发现class里面并没有这个方法,通过class里面的super_class找到Parent的class,在里面的方法列表找到了SelectorP;

5,再是类方法[Child ClassSelectorC],Child(请注意,大写)通过isa找到Child的class,通过class的isa找到Child的metaclass,在metaclass的方法列表里面找到了ClassSelectorC;

6,再试着调用[Child ClassSelectorP],Child通过isa找到Child的class,通过class的isa找到Child的metaclass,发现metaclass里面并没有这个方法,通过metaclass里面的super_class找到Parent的metaclass,在里面的方法列表找到了ClassSelectorP;  

- (void)viewDidLoad {
[super
viewDidLoad];
Class clazz = [self
class];
Class clarr = [AroundMapController
class];
Class metalclazz =
objc_getMetaClass("AroundMapController");
if (class_respondsToSelector(metalclazz,
@selector(viewWillAppear:))) {
NSLog(@"ok");
}
if (clarr == clazz) {
NSLog(@"2 ok");
}
}
这个是验证runtime的机制,可以把这段代码复制到自己的controller.m里面,运行一下。记得把AroundMapController改成自己的controller的名字,还有引入头文件<objc/runtime.h>

这是几个例子基本上已经涵盖了大多数调用的情况。

细心的朋友可能已经发现,上面的例子中,child通过isa找到的类对象,其实就是Child 通过isa找到的class。(如果能理解这一点,基本上也算对objectC的isa机制也算入门)

最后为了理解class和metaclass的作用,大家可以换位思考一下,如果我们作为runtime的设计者,当开发者新建出来一个实例对象child的时候,我们应该存储child的属性和方法,同时又该如何响应其方法调用,最后还要记录与Parent之间的继承关系。

这时候,再来看看,这种图。可以加深对isa机制的理解:



参考
http://www.cocoachina.com/ios/20141018/9960.html http://blog.csdn.net/jasonblog/article/details/7246822 http://blog.csdn.net/totogo2010/article/details/8081253

一.isa指针

要认识什么是isa指针,我们得先明确一点:

在Objective-C中,任何类的定义都是对象。类和类的实例(对象)没有任何本质上的区别。任何对象都有isa指针。

那么什么是类呢?在xcode中用快捷键Shift+Cmd+O 打开文件objc.h 能看到类的定义:



可以看出:

Class 是一个 objc_class 结构类型的指针, id是一个 objc_object 结构类型的指针.

我们再来看看 objc_class 的定义:



稍微解释一下各个参数的意思:

isa:是一个Class 类型的指针. 每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass).根元类的isa指针指向本身,这样形成了一个封闭的内循环。

super_class:父类,如果该类已经是最顶层的根类,那么它为NULL。

version:类的版本信息,默认为0

info:供运行期使用的一些位标识。

instance_size:该类的实例变量大小

ivars:成员变量的数组

再来看看各个类实例变量的继承关系:



每一个对象本质上都是一个类的实例。其中类定义了成员变量和成员方法的列表。对象通过对象的isa指针指向类。

每一个类本质上都是一个对象,类其实是元类(meteClass)的实例。元类定义了类方法的列表。类通过类的isa指针指向元类。

所有的元类最终继承一个根元类,根元类isa指针指向本身,形成一个封闭的内循环。

二.runtime 机制

runtime:指一个程序在运行(或者在被执行)的状态。也就是说,当你打开一个程序使它在电脑上运行的时候,那个程序就是处于运行时刻。在一些编程语言中,把某些可以重用的程序或者实例打包或者重建成为“运行库"。这些实例可以在它们运行的时候被连接或者被任何程序调用。

objective-c中runtime:是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API。 在我们平时编写的OC代码中, 程序运行过程时, 其实最终都是转成了runtime的C语言代码。

runtime的应用:

1.动态创建一个类(比如KVO的底层实现)

2.动态地为某个类添加属性\方法, 修改属性值\方法

3.遍历一个类的所有成员变量(属性)\所有方法

实质上,以上的是通过相关方法来获取对象或者类的isa指针来实现的。

相关函数



1. 增加

增加函数:class_addMethod

增加实例变量:class_addIvar

增加属性:@dynamic标签,或者class_addMethod,因为属性其实就是由getter和setter函数组成

增加Protocol:class_addProtocol (说实话我真不知道动态增加一个protocol有什么用,-_-!!)

2. 获取

获取函数列表及每个函数的信息(函数指针、函数名等等):class_getClassMethod method_getName ...

获取属性列表及每个属性的信息:class_copyPropertyList property_getName

获取类本身的信息,如类名等:class_getName class_getInstanceSize

获取变量列表及变量信息:class_copyIvarList

获取变量的值

3. 替换

将实例替换成另一个类:object_setClass

替换类方法的定义:class_replaceMethod

4.其他常用方法:

交换两个方法的实现:method_exchangeImplementations.

设置一个方法的实现:method_setImplementation.

文/曲年(简书作者)

原文链接:http://www.jianshu.com/p/41735c66dccb

著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: