集美阅读大全是一个以文章句子为主题的在线阅读网站。内含有各种经典好文章,爱情美文,诗歌散文,情感句子说说,范文资料等。读好文章,尽在集美阅读大全!!!
当前位置:集美阅读大全 >杂文 > 正文

iOS-对象、isa和SuperClass

2019-09-18 16:47SuperClass 对象 iOS isa

前言:本文简述OC对象、isa和SuperClass,如有错误请留言指正。

Q:OC中对象分类

A:总共为三类:实例对象、类对象、元类对象

  • instance对象(实例对象)
  • class对象(类对象)
  • meta-class对象(元类对象)

实例对象(instance)

  • instance对象就是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象
<code>Student *p1 = [[Student alloc] init]; Student *p2 = [[Student alloc] init]; 
  • p1、p2是Student的instance对象(实例对象),它们是不同的两个对象,分别占据着两块不同的内存

    p1、p2内存地址

instance对象在内存中存储的信息包括

  • isa指针
  • 其他成员变量的值
  • 实例对象不包含实现方法

类对象(Class)

NSObject *obj1 = [[NSObject alloc] init]; Class objClass1 = [obj1 class]; Class objClass2 = [NSObject class]; //class 方法返回的一直是class对象,类对象,而不是元类对象 Class objClass3 = [[NSObject class] class]; Class objClass4 = object_getClass(obj1); NSLog(@"%p-%p-%p-%p",objClass1,objClass2,objClass3,objClass4); 
  • 上述都是同一个类对象,打印出的地址相同,每个类在内存中有且只有一个class对象

class对象在内存中存储的信息包括

  • isa指针
  • superclass指针
  • 类的属性信息(@property)
  • 类的实例方法信息(instance method)
  • 类的协议信息(protocol)
  • 类的成员变量信息(ivar)(成员变量类型、名称等等,不是成员变量的值)
  • ……

元类对象(meta-class)

Class metaClass = object_getClass([NSObject class]); 
  • 每个类在内存中有且只有一个meta-class对象
  • meta-class对象和class对象的内存结构是一样的,但是用途不一样

在内存中存储的信息主要包括

  • isa指针
  • superclass指针
  • 类的类方法信息(class method)
  • ……
方法说明

1.Class objc_getClass(const char *aClassName)

  • 1> 传入字符串类名
  • 2> 返回对应的类对象

2.Class object_getClass(id obj)

  • 1> 传入的obj可能是instance对象、class对象、meta-class对象
  • 2> 返回值
    a) 如果是instance对象,返回class对象
    b) 如果是class对象,返回meta-class对象
    c) 如果是meta-class对象,返回NSObject(基类)的meta-class对象

Q:实例对象、类对象isa指向

A:instance的isa指向class,class的isa指向meta-class

  • 当调用实例方法时,通过instance的isa找到class,最后找到实例方法的实现进行调用
  • 当调用类方法时,通过class的isa找到meta-class,最后找到类方法的实现进行调用

    isa指向

Q:对象的isa指针指向哪里?

A:根据不同类型的对象来回答。

  • instance对象的isa指向class对象
  • class对象的isa指向meta-class对象
  • meta-class对象的isa指向基类的meta-class对象

Q:OC的类信息存放在哪里?

A:类的内容分别作答。

  • 实例方法、属性、成员变量、协议信息,存放在class对象中
  • 类方法,存放在meta-class对象中
  • 成员变量的具体值,存放在instance对象

Q问题描述:Student类继承自Person;Person继承自NSObject

示例代码:

@interface Person : NSObject<NSCopying> {     int _age;     int _name;     int _bro; } - (void)personInstanceMethod; + (void)personClassMethod; @end  @implementation Person - (void)personInstanceMethod{      } + (void)personClassMethod{      } - (id)copyWithZone:(NSZone *)zone{     return nil; } @end  @interface Student : Person<NSCopying> {     int _dog;     int _cat;     int _book;          int _phone;     int _bicycle;          int _hat;     int _clothes;     int _pants; } - (void)studentInstanceMethod; + (void)studentClassMethod; @end  @implementation Student - (void)studentInstanceMethod{} + (void)studentClassMethod{} @end  
q1:上述代码各类对象superclass指向?
a1:各类的superclass指向父类对象

类对象的superclass指针指向父类对象

各类superclass指向

q2:Student实例对象调用Student实例方法的调用流程?

示例代码:

Student *stu = [[Student alloc] init]; [stu studentInstanceMethod]; 

a2:stu实例对象isa找到Student的类对象,调用实例方法

实例对象调用实例方法流程

q3:Student实例对象调用Person实例方法的调用流程?

示例代码:

Student *stu = [[Student alloc] init]; [stu personInstanceMethod]; 

a3:stu实例对象isa找到Student的类对象,通过Student的superclass找到Person的类对象,最后调用Person的实例方法实现。

stu调用Person实例方法流程

q4:Student实例对象调用init方法的调用流程?

示例代码:

Student *stu = [[Student alloc] init]; [stu init]; 

a3:调用流程

  • 1.stu实例对象isa找到Student的类对象
  • 2.通过Student的superclass找到Person的类对象
  • 3.通过Person的superclass找到NSObject的类对象
  • 4.最后调用NSObject的init方法实现。

Q:Student类继承自Person;Person继承自NSObject,各类元类的superclass指针指向?

A:Student元类superclass指向Person的元类,Person元类superclass指向NSObject的元类

各类元类的superclass指针指向

q1:参考上述示例,[Student studentClassMethod] 调用流程
a1:Student类isa指针找到 Student元类,然后调用类方法 studentClassMethod

q2:参考上述示例,[Student personClassMethod] 调用流程
a3:Student类isa指针找到 Student元类,Student元类的superclass找到Person元类,再调用personClassMethod

q2:参考上述示例,[Student load] 调用流程
a3:Student类isa指针找到 Student元类,Student元类的superclass找到Person元类,Person元类的superclass找到NSObject元类,再调用load

isa、superclass 小结

  • instance的isa指向class
  • class的isa指向meta-class
  • meta-class的isa指向基类的meta-class
  • class的superclass指向父类的class,如果没有父类,superclass指针为nil
  • meta-class的superclass指向父类的meta-class;基类的meta-class的superclass指向基类的class
  • instance调用实例方法的轨迹;isa找到class,方法不存在,就通过superclass找父类
  • class调用类方法的轨迹;isa找meta-class,方法不存在,就通过superclass找父类

isa、superclass指向

上述图片备注:isa指向为虚线、superclass指向为实线,Root class元类的superclass指向Root class的class(转弯处实线)。可以按照Student、Person、NSObject来理解。

  • 如果在基类中找不到方法实现,会报错unrecognized selector sent to class 0x1000011**

Q:如果调用类方法没有实现,是否会调用同名的实例方法。

A:会。

调用方法实质是runtime的消息转发机制,runtime只会根据方法名寻找而不会在意是类方法还是实例方法。
代码验证:

#Person文件 @interface Person : NSObject + (void)test; @end  @implementation Person + (void)test{     NSLog(@"+[Person test] %p",self); } @end  #NSObject+Test文件 @interface NSObject (Test) + (void)test; @end  @implementation NSObject (Test) + (void)test{     NSLog(@"+[NSObject test] %p",self); } @end  #调用方式:  NSLog(@"Person:%p",[Person class]); NSLog(@"NSObject:%p",[NSObject class]); [Person test]; [NSObject test]; 
输出结果1:

Person:0x10e72e090
NSObject:0x10f6d8ea8
+[Person test] 0x10e72e090
+[NSObject test] 0x10f6d8ea8

输出结果2:(如果将Person的类方法注释掉,其余代码不变)
#Person 文件 @interface Person : NSObject + (void)test; @end  @implementation Person //+ (void)test{ //    NSLog(@"+[Person test] %p",self); //} @end 

输出结果2:
Person:0x10477b050
NSObject:0x105725ea8
+[NSObject test] 0x10477b050
+[NSObject test] 0x105725ea8

因为Person里找不到test实现方法,即找父类的实现方法

输出结果3:(如果将Person和NSObject的类方法注释掉,其余代码不变)
#Person 文件 @interface Person : NSObject + (void)test; @end  @implementation Person //+ (void)test{ //    NSLog(@"+[Person test] %p",self); //} @end  #NSObject+Test文件 @interface NSObject (Test) + (void)test; @end  @implementation NSObject (Test) //+ (void)test{ //    NSLog(@"+[NSObject test] %p",self); //} @end 

输出结果3:会报错
Person:0x10766efd0
NSObject:0x108618ea8
+[Person test]: unrecognized selector sent to class 0x10766efd0
*** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘+[Person test]: unrecognized selector sent to class 0x10766efd0’

输出结果4:(如果将Person和NSObject的类方法注释掉,NSObject添加对象同名方法,其余代码不变)
#Person 文件 @interface Person : NSObject + (void)test; @end  @implementation Person //+ (void)test{ //    NSLog(@"+[Person test] %p",self); //} @end  #NSObject+Test文件 @interface NSObject (Test) + (void)test; @end  @implementation NSObject (Test) - (void)test{     NSLog(@"-[NSObject test] %p",self); }  //+ (void)test{ //    NSLog(@"+[NSObject test] %p",self); //} @end 

输出结果4:
Person:0x101656010
NSObject:0x102600ea8
-[NSObject test] 0x101656010
-[NSObject test] 0x102600ea8

由此可见,当类方法无实现时,会调用同名的实例方法,上述辩证方法验证了isa、superclass指向图中的meta-Root class的superclass指向Root class(上图实线转弯处)。

Q:讨论isa指针值

从64bit开始,isa需要进行一次位运算,才能计算出真实地址
示例代码:

struct xbt_objc_class {     Class isa ; };  Person *p = [[Person alloc] init]; Class pClass = [Person class]; Class personMetaClass = object_getClass(pClass); struct xbt_objc_class *pClass1 = (__bridge struct xbt_objc_class *)pClass; NSLog(@"%p-%p-%p",p,pClass,personMetaClass); 

LLDB 命令行查看isa值

(lldb) p p->isa//获取不到真正的isa指针 (Class) $0 = Person (lldb) p/x (long)p->isa (long) $1 = 0x000001a100105311//实例对象isa指针 (lldb) p/x pClass (Class) $2 = 0x0000000100105310 Person//类对象地址 (lldb) p/x 0x000001a100105311 & 0x0000000ffffffff8//进行换算 (long) $3 = 0x0000000100105310  (lldb) p/x pClass1->isa (Class) $0 = 0x000001a10402d2e9//类对象isa指针值 (lldb) p/x personMetaClass (Class) $1 = 0x000000010402d2e8//元类对象isa指针值 (lldb) p/x 0x000001a10402d2e9 & 0x0000000ffffffff8//进行换算 (long) $2 = 0x000000010402d2e8 0x1c0036780-0x102a41310-0x102a412e8 

结果可见:
1.实例对象isa值为0x000001a100105311
2.类对象地址为0x0000000100105310
3.换算结果:实例对象isa指针值 &0x0000000ffffffff8才与类对象地址值相同
4.类对象isa指针为0x000001a10402d2e9。(类并没有暴露出isa指针值,定义了一个和类相似的结构体xbt_objc_class,进行强制转换后,才获取到类对象的isa指针)
5.元类对象地址为0x000000010402d2e8
6.换算结果:类对象isa指针值 &0x0000000ffffffff8才与元类对象地址值相同

总结

  • 从64bit开始,isa需要进行一次位运算,才能计算出真实地址
  • isa指针需要 & ISA_MASK 值才是最终结果
  • runtime中ISA_MASK值:
# if __arm64__//iPhone #   define ISA_MASK        0x0000000ffffffff8ULL # elif __x86_64__//mac #   define ISA_MASK        0x00007ffffffffff8ULL 

Q:讨论superclass指针值,是否会想isa指针值一样?

A:superclass指针值与指向对象地址相同,和isa指针值不一样

代码证明
前提:student继承自Person,写结构体来代替类

struct xht_objc_class {     Class isa ;     Class superclass ; }; struct xht_objc_class *pClass = (__bridge struct xht_objc_class *)[Person class]; struct xht_objc_class *stuClass = (__bridge struct xht_objc_class *)[Student class]; NSLog(@"%p-%p",pClass,stuClass); 

LLDB调试

(lldb) p/x stuClass->superclass (Class) $0 = 0x0000000102299340 Person//Student类的superClass值 (lldb) p/x pClass (xht_objc_class *) $1 = 0x0000000102299340//Person类地址 

综上所述,Student类的superClass值 = Person类地址

Q:类的本质结构

类的本质是结构体
附上runtime的结构体代码

#objc_class:objc_object struct objc_class : objc_object {     // Class ISA;     Class superclass;     //方法缓存     cache_t cache;             // formerly cache pointer and vtable     //用于获取具体类信息     class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags      class_rw_t *data() {          return bits.data();     }     // 诸多方法 }  #class_rw_t struct class_rw_t {     // Be warned that Symbolication knows the layout of this structure.     uint32_t flags;     uint32_t version;      const class_ro_t *ro;//只读类表      method_array_t methods;//方法列表     property_array_t properties;//属性列表     protocol_array_t protocols;//协议列表      // 诸多方法 }  #class_ro_t struct class_ro_t {     uint32_t flags;     uint32_t instanceStart;     uint32_t instanceSize;//instance对象占用的内存空间 #ifdef __LP64__     uint32_t reserved; #endif      const uint8_t * ivarLayout;          const char * name;//类名     method_list_t * baseMethodList;     protocol_list_t * baseProtocols;     const ivar_list_t * ivars;//成员变量列表      const uint8_t * weakIvarLayout;     property_list_t *baseProperties;      method_list_t *baseMethods() const {         return baseMethodList;     } };  #objc_object struct objc_object { private:     isa_t isa;//类的isa指针是私有的  public:       // 诸多方法 } 

结构体结构

想LLDB命令查看相关类结构,可以采取仿写类结构进行打印查看

奉上大神的杰作

#import <Foundation/Foundation.h>  #ifndef xbtClassInfo_h #define xbtClassInfo_h  # if __arm64__ #   define ISA_MASK        0x0000000ffffffff8ULL # elif __x86_64__ #   define ISA_MASK        0x00007ffffffffff8ULL # endif  #if __LP64__ typedef uint32_t mask_t; #else typedef uint16_t mask_t; #endif typedef uintptr_t cache_key_t;  struct bucket_t {     cache_key_t _key;     IMP _imp; };  struct cache_t {     bucket_t *_buckets;     mask_t _mask;     mask_t _occupied; };  struct entsize_list_tt {     uint32_t entsizeAndFlags;     uint32_t count; };  struct method_t {     SEL name;     const char *types;     IMP imp; };  struct method_list_t : entsize_list_tt {     method_t first; };  struct ivar_t {     int32_t *offset;     const char *name;     const char *type;     uint32_t alignment_raw;     uint32_t size; };  struct ivar_list_t : entsize_list_tt {     ivar_t first; };  struct property_t {     const char *name;     const char *attributes; };  struct property_list_t : entsize_list_tt {     property_t first; };  struct chained_property_list {     chained_property_list *next;     uint32_t count;     property_t list[0]; };  typedef uintptr_t protocol_ref_t; struct protocol_list_t {     uintptr_t count;     protocol_ref_t list[0]; };  struct class_ro_t {     uint32_t flags;     uint32_t instanceStart;     uint32_t instanceSize;  // instance对象占用的内存空间 #ifdef __LP64__     uint32_t reserved; #endif     const uint8_t * ivarLayout;     const char * name;  // 类名     method_list_t * baseMethodList;     protocol_list_t * baseProtocols;     const ivar_list_t * ivars;  // 成员变量列表     const uint8_t * weakIvarLayout;     property_list_t *baseProperties; };  struct class_rw_t {     uint32_t flags;     uint32_t version;     const class_ro_t *ro;     method_list_t * methods;    // 方法列表     property_list_t *properties;    // 属性列表     const protocol_list_t * protocols;  // 协议列表     Class firstSubclass;     Class nextSiblingClass;     char *demangledName; };  #define FAST_DATA_MASK          0x00007ffffffffff8UL struct class_data_bits_t {     uintptr_t bits; public:     class_rw_t* data() {         return (class_rw_t *)(bits & FAST_DATA_MASK);     } };  /* OC对象 */ struct xbt_objc_object {     void *isa; };  /* 类对象 */ struct xbt_objc_class : xbt_objc_object {     Class superclass;     cache_t cache;     class_data_bits_t bits; public:     class_rw_t* data() {         return bits.data();     }          xbt_objc_class* metaClass() {         return (xbt_objc_class *)((long long)isa & ISA_MASK);     } };  #endif /* xbtClassInfo_h */ 

您可能感兴趣的文章

  • Android2018面试题总结(真的很全面哦~ Android篇)
  • 超详细,超系统的JavaScript学习笔记—JS面向对象程序设计
  • java子类调用父类的方法中包含子类重写的实例方法
  • Java设计模式简介
  • 全方位解读Java反射(reflection)
  • iOS Runtime详解
  • isMemberOfClass、isKindOfClass原理分析
  • java学习笔记(基础篇)—面向对象编程之封装、继承、多态 – chlinlearn

未经允许不得转载:杂烩网 » iOS-对象、isa和SuperClass

课后答案张九龄《望月怀远》阅读答案及全诗翻译赏析

望月怀远张九龄海上生明月,天涯共此时。情人怨遥夜,竟夕起相思。灭烛怜光满,披衣觉露滋。不堪盈手赠,还寝梦佳期。注释⑴怀远:怀念远方的亲人。⑵最前面两句:辽阔无边的大海上升起一轮明月,使人想起了远在天涯……
2023-11-22 04:53暂无评论阅读详情

课后答案王安石《次韵唐公三首其三旅思》阅读答案

次韵唐公三首其三旅思王安石此身南北老,愁见问征途。地大蟠三楚,天低入五湖。看云心共远,步月影同孤。慷慨秋风起,悲歌不为鲈②。注:①张壤,字唐公,北宋嘉佑六年契丹国母生辰使,王安石友人。②《晋书&mid……
2023-11-22 04:52暂无评论阅读详情

笔记心得各级干部学习执法为民心得体会

  &ldquo;各级干部都要牢固树立全心全意为人民服务的思想和真心实意对人民负责的精神,做到心里装着群众,凡事想着群众,工作依靠群众,一切为了群众。要坚持权为民所用,情为民所系,利为民所谋,为群众诚……
2023-11-22 04:12暂无评论阅读详情

笔记心得寒假大学生社会实践心得体会

  自从走进了大学,就业问题就似乎总是围绕在我们的身边,成了说不完的话题。在现今社会,招聘会上的大字报都总写着&ldquo;有经验者优先&rdquo;,可还在校园里面的我们这班学子社会经验又会拥有多少……
2023-11-22 04:08暂无评论阅读详情

协议书济南市某美容院转让协议第2篇

&nbsp;&nbsp;__________美容院根据中华人民共和国国务院劳动法规和________市私营企业劳动管理实施办法,结合本美容院经营的具体所需今制订此劳动合同书。&nbsp;&nbsp;双……
2023-11-22 02:36暂无评论阅读详情

剧本劳模宣传短剧剧本《阿咪也想当劳模》

  1、机械厂门卫处,日,外。  清早,机械厂班长李玉伟开着别克赛欧小汽车驶进厂区,门卫室内的保安一边按开电动门,一边朝李玉伟摆手。  李玉伟:(摇下车窗,笑着打招呼)小秦,早。  保安小秦:(笑着)……
2023-11-22 02:11暂无评论阅读详情

教程灰雀说课稿

灰雀说课稿  灰雀说课稿(一):  《灰雀》说课稿  一、说教材  《灰雀》是义务教育课程标准实验教科书,小学语文第五册第二单元的一篇讲读课文。这篇课文记叙了列宁在莫斯科郊外养病期间爱护灰雀的故事。列……
2023-11-22 00:41暂无评论阅读详情

课件“吴隐之字处默,濮阳鄄城人”阅读答案及原文

吴隐之字处默,濮阳鄄城人。美姿容,善谈论,博涉文史,以儒雅标名。弱冠而介立,有清操,虽儋石无储,不取非其道。事母孝谨,及其执丧,哀毁过礼。与太常韩康伯邻居,康伯母,贤明妇人也,每闻隐之哭声,辍餐投箸,……
2023-11-22 00:38暂无评论阅读详情

标签