iOS 中得isa 和self 的详解

其他废话我就不多讲了,谈一谈我对self 和 isa的理解!主要是和java对比: 
self概念上的理解上我认为和java中的this是一样的,当然,底层的实现是有区别的,毕竟是不同平台的两个语言,但是他们的概念的理解是一样的。就是在类实例化对象时,self指向了对象的首地址。 
isa则相当于java中每个对象的class,就像我们平时写的,XXX.getClass()或XXX.class。OC中的isa指向了其类对象,想一下,我们在java中使用反射时不都是需要取得其类对象嘛!OC也一样,类对象isa也是用在运行时获取对象的类信息的。这样说其实和java中的class概念是一致的。大家可以参考这篇文章:http://blog.sina.com.cn/s/blog_7a2ffd5c01010nme.html 
《Object-C基础教程》中有提到:“self指向的对象的首地址,而对象的首地址是isa变量”这样说不容易理解,会让人误会self 和 isa指向了同一个东西,应该是这样:self指向了对象的首地址,而对象的首地址一般是isa变量,isa又是保存了对象的类对象的首地址!汗,好像还是很绕,反正就是这两个变量其实是各有各的用处就是了。 
-------------------------------------分割线------------------------------------------- 
从这里顺便提一下子类的self和父类的self 
我们初始化一个对象时会看到:self=[super init],先将父类初始化,然后再把父类的self赋给子类的self,这里又有点绕了,其实,父类的self和子类的self是同一个(正常情况下);那为什么要赋给子类的self呢?这就是因为有“非正常”的情况存在,大家可自行查阅,文章非常多。这里主要解释一下为什么父类的self和子类的self是同一个,我们平时看到很多文章会这么说:子类拥有一个父类的引用(无论是java还是OC都会这么说),我觉得这样说是不准确的说法,如果为了容易理解可以这么说。因为,如果只是简单的子类拥有父类的引用的话,父类的self和子类的self应该是不同的。和java一样,父类的this和子类的this也是同样的道理,我们用java做个试验: 
Java代码   收藏代码
  1. public class Father {  
  2.   
  3.     public Father print(){  
  4.         return this;  
  5.     }  
  6. }  
  7.   
  8. public class Sun extends Father {  
  9.     Test t = new Test();  
  10.     public void printSun(){  
  11.         t.print();  
  12.           
  13.         System.out.println(super.toString());  
  14.         System.out.println(super.print());  
  15.         System.out.println(this);  
  16.     }  
  17.       
  18.     public static void main(String args[]){  
  19.         Sun sun = new Sun();  
  20.           
  21.         sun.printSun();  
  22.     }  
  23.   
  24.   
  25. public class Test {  
  26.   
  27.     public void print(){  
  28.         System.out.println("i am test this : " + this);  
  29.     }  
  30. }  

打印结果: 
i am test this : Test@c17164 
Sun@1fb8ee3 
Sun@1fb8ee3 
Sun@1fb8ee3 

我们看到,父类this和子类this是一样的,但是如果只是简单拥有一个引用,那么应该和Test的引用一样,是不一样的所以,说明父类和子类之间不是简单的拥有一个引用,我感觉是子类会把父类通过某种机制“包含”进来! 
以上是本人粗浅的理解,欢迎批评指正!毕竟初学,希望和大家一起进步。 

--------------------------------------------华丽丽的 分割线----------------------------------- 

object-c是动态语言,使用反射,还有动态往对象加方法等等一切动态的灵活性,都是因为有一个特殊的“代理”runtime,cocoa编程语言介绍如是说:因此这种动态性就需要借助Objective-C Runtime来实现,也就是说运行时我们除了有程序代码外还需要一个Objective C Runtime来协助完成程序的运行,这一点类似于Java的虚拟机。


[0] Outline

  -- [1] id和Class

  -- [2] 动态地操作类

  -- [3] 实例化


[1] id和Class

在Objective-C中有一个特别的数据类型作为对象标识符:id,可以指向任何类型的对象。

通过 “可以指向任何类型的对象” 这一描述,猜想id实际上是指向Objective-C对象系统中的基类(继承体系中的祖先结构)的指针,在运行时是指向对象内存布局的基类部分。


第一眼看到id数据类型,我联想到了Python中的PyObject结构:

[cpp]  view plain copy
  1. typedef struct _object {  
  2.     int ob_refcnt;  
  3.     struct _typeobject *ob_type;  
  4. } PyObject;  

该数据类型也是Python对象系统中的祖先类型,不过与id相对应的应该是PyObject *类型。


id数据类型是一个指向struct objc_object结构的指针:

[cpp]  view plain copy
  1. typedef struct objc_class *Class;  
  2. typedef struct objc_object {  
  3.     Class isa;  
  4. } *id;  

更确切地说,id是指向Class类型的指针,而Class又是指向struct objc_class结构的指针:

[cpp]  view plain copy
  1. struct objc_class {  
  2.      struct objc_class *isa;  
  3.   
  4.      struct objc_class *super_class;   
  5.      const char *name;    
  6.      long version;  
  7.      long info;  
  8.      long instance_size;  
  9.      struct objc_ivar_list *ivars;  
  10.      struct objc_method_list **methodLists;  
  11.      struct objc_cache *cache;  
  12.      struct objc_protocol_list *protocols;  
  13. };  

至此,可以看到Objective-C对象系统的基石:struct objc_class结构:

[cpp]  view plain copy
  1. isa指针:指向该对象所属类型的类型对象(Class Object)。在Objective-C中,类也是用对象来表示的,而类的isa指针指向它的metaclass(存储静态成员变量和类方法)。  
  2. super_class指针:指向父类。  
  3. name:类名称。  
  4. version:类的版本信息。  
  5. info:运行期使用的标志位,比如0x1(CLS_CLASS)表示该类为普通class,0x2(CLS_META)表示该类为     metaclass。  
  6. instance_size:实例大小,即内存所占空间。  
  7. ivars:指向成员变量列表的指针。  
  8. methodLists:根据标志位的不同可能指向不同,比如可能指向实例方法列表,或者指向类方法列表。  
  9. cache:因为Objective-C的消息转发需要查找dispatch table甚至可能需要遍历继承体系,所以缓存最近使用的方法。  
  10. protocols:类需要遵守的协议。  

[2] 动态地操作类

由上知道了类也是一种对象,那么类对象也有一种类型,这种类型就是类的metaclass,因此类方法其实就是metaclass的成员方法,类和metaclass是配套出现的。

那么metaclass的isa指针和super_class指针怎么指向的呢?

如果metaclass对应基类,那么它的isa指向自身、super_class指针指向对应的类(基类);如果不是则isa指针指向基类的metaclass、super_class指针指向父类的metaclass。

基类的isa指针为nil。


这不禁让我又想起了Python中类似的设计思想,比如整型数字2的类型是PyIntObject,而PyIntObject类的类型是PyTypeObject,PyTypeObject的类型是PyTypeObject。最终止于此。

同样地,Python中也有metaclass的存在。


知道了类的表示结构,我们可以动态地对类进行操作,加深理解。

[cpp]  view plain copy
  1. //  
  2. //  main.m  
  3. //  HelloOC  
  4. //  
  5. //  Created by Jason Lee on 12-2-17.  
  6. //  Copyright (c) 2012年 XXX. All rights reserved.  
  7. //  
  8.   
  9. #import <Foundation/Foundation.h>  
  10.   
  11. #import <objc/objc.h>  
  12. #import <objc/runtime.h>  
  13.   
  14. void selfIntro(idself, SEL_cmd);  
  15.   
  16. int main (int argc, constchar * argv[])  
  17. {  
  18.       
  19.     @autoreleasepool {  
  20.         //Create class & metaclass as a pair  
  21.         Class demoClass = objc_allocateClassPair([NSObjectclass], "NSDemo", 0);  
  22.           
  23.         BOOL isOk = NO;  
  24.           
  25.         //"v@:" indicates the function type : v - void, @ - object, : - SEL  
  26.         //向methodLists指向添加数据  
  27.         isOk = class_addMethod(demoClass, @selector(intro), (IMP)&selfIntro, "v@:");  
  28.         isOk == YES ? nil : NSLog(@"failed on class_addMethod\n");  
  29.           
  30.         //向ivars指向添加数据  
  31.         isOk = class_addIvar(demoClass,"myVar"sizeof(id), log2(sizeof(id)), "@");   
  32.         isOk == YES ? nil : NSLog(@"failed on class_addIvar\n");  
  33.           
  34.         objc_registerClassPair(demoClass);  
  35.           
  36.         id demo = class_createInstance(demoClass, 0);  
  37.           
  38.         if ([demo respondsToSelector:@selector(intro)]) {  
  39.             [demo performSelector:@selector(intro)];  
  40.         }  
  41.           
  42.         object_setInstanceVariable(demo, "myVar", nil);  
  43.         void *outValue = (void *)0x1;  
  44.         object_getInstanceVariable(demo, "myVar", &outValue);  
  45.         if (nil == outValue) {  
  46.             NSLog(@"Hello,nil\n");  //printed  
  47.         }  
  48.           
  49.         object_dispose(demo);  
  50.     }  
  51.       
  52.     return0;  
  53. }  
  54.   
  55. void selfIntro(idself, SEL_cmd) {  
  56.     NSLog(@"selfIntro\n");  
  57.       
  58.     Class isa = self->isa;  //At first, isa is class NSDemo  
  59.     while (1) {  
  60.         if (isa == isa->isa) {  //Finally, NSObject's metaclass points to itself  
  61.             NSLog(@"%p, %@", isa, objc_getMetaClass(class_getName([isa class])));  
  62.             break;  
  63.         }  
  64.           
  65.         NSLog(@"%p, %@", isa, objc_getMetaClass(class_getName([isa class])));  
  66.         isa = isa->isa; //Then, isa is assigned to NSDemo's metaclass  
  67.     }  
  68. }  


[3] 实例化

要实例化出一个对象,需要根据类的定义来进行。类的定义包括类名称、数据和操作数据的方法。

编译过程,类的信息会被记录下来,供runtime system使用,同时编译器会为每个类创建唯一的一个对象来表示它:class object。如果从功能上说,class object也是factory object,它能够执行类方法,负责创建实例。


从这个角度来看,我在思考class object是否就是metaclass,但是不能确认。

Apple官方文档TOCPL中Class Objects一章有这么一句,“a class object keeps the prototype of a class instance”,但metaclass并不能作为实例原型。

于是我认为class object是运行时class和metaclass结合起来的受限表现,能够访问编译器捕捉下来的类信息,没有成员变量,不能调用成员方法,但是可以执行类方法。

从源码层次来看,class object是由类名来表示,比如下述代码中:

[cpp]  view plain copy
  1. int version = [NSString version];  

NSString代表着class object。


首先,class object会被runtime system发送initialize消息进行初始化,让其做好运行时的准备,比如初始化静态变量。

之后,可以调用class object的方法(类方法)alloc来为新的实例对象分配内存空间,将其所有变量初始化为0,isa指针指向所属类。

最后再调用init函数进行必要的初始化。


写到这里的时候,突然要变更办公位置,思路被打断了,就先写到这里。

最后,留一个在SO上面看到的问题,我也疑惑,只能有几分猜测:http://stackoverflow.com/questions/8847146/whats-is-methodlists-attribute-of-the-structure-objc-class-for

[这篇文章是我对SO上的问题的解答:http://blog.csdn.net/jasonblog/article/details/7303618]





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值