1. 类的底层实现

先写一个 Person 类:

@interface Person : NSObject
@property (nonatomic, copy) NSString *p_name;
@property (nonatomic, assign) int p_age; - (void)p_instanceMethod1;
@end @implementation Person
- (void)p_instanceMethod1{
NSLog(@"%s",__func__);
}
@end

使用 clang 编译器, clang -rewrite-objc Person.m -o Person.cpp  将 Person.m  编译成 Person.cpp 文件,部分代码如下:

/// 1: Person 类型的底层结构
struct NSObject_IMPL {
Class isa;
}; struct Person_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _p_age;
NSString * _Nonnull _p_name;
}; /// 2: p_name 属性的底层结构
// get
static NSString * _Nonnull _I_Person_p_name(Person * self, SEL _cmd) { return (*(NSString * _Nonnull *)((char *)self + OBJC_IVAR_$_Person$_p_name)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
// set
static void _I_Person_setP_name_(Person * self, SEL _cmd, NSString * _Nonnull p_name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct Person, _p_name), (id)p_name, 0, 1); } /// 3: p_age 类型的底层结构
// get
static int _I_Person_p_age(Person * self, SEL _cmd) { return (*(int *)((char *)self + OBJC_IVAR_$_Person$_p_age)); }
// set
static void _I_Person_setP_age_(Person * self, SEL _cmd, int p_age) { (*(int *)((char *)self + OBJC_IVAR_$_Person$_p_age)) = p_age; } /// 4: p_instanceMethod1 方法的底层结构
static void _I_Person_p_instanceMethod1(Person * self, SEL _cmd) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_86_0y_j3bzj65z6vw6hy1chw_4m0000gp_T_Person_f010c0_mi_0,__func__);
}
  • NSObject 类被编译成了 NSObject_IMPL 的结构体。
  • Person 类被编译成了 Person_IMPL 的结构体。
  • Person 类的内部还增加了一个 NSObject_IMPL 的结构体
    • 我们知道 Person 继承于 NSObject, 所以它的底层实现中是第一个成员是父类的结构体,就是底层继承的实现方式。用这样的方式拥有父类所有的成员变量。
    • NSObject_IMPL 是 NSObject 类的编译后的结构体,它的内部只有一个 Class 类型的 isa 成员变量。我们知道 isa 是 isa_t 类型的,那为什么在这里定义成 Class 类型呢?这是为了更加直观的提现出它代表的是类的信息,所以在获取isa 的方法中,将它强制转换成了Class 类型, 代码如下:
inline Class objc_object::ISA() {

    ...

    return (Class)(isa.bits & ISA_MASK)
}

总结:

1.类的底层实现是结构体。

2.继承是通过把父类的结构体声明为本类结构体的第一个成员变量实现的。

2. isa_t 的类型

联合体: 所有成员可以是不同的类型,但是公用一块内存区域,设置了一个成员变量就会覆盖另一个成员变量的数据。优点是节省空间。

union isa_t { //联合体
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
//提供了cls 和 bits ,两者是互斥关系
Class cls;
uintptr_t bits;
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD; // defined in isa.h
};
#endif
};

isa 指针占用8字节,64位。64位中不同的位代表不同的含义:

对象与类的 isa 的指向关系

对象.isa -> 类.super -> 父类.super -> 根类.super -> nil

类.isa -> 元类.super -> 父元类.super -> 根元类.super -> 根类.super -> nil

元类.isa = 父元类.isa = 根元类.isa = 根元类

应用:判断对象类型

下面的打印结果是什么:

// [NSObject class] = NSObject
// object_getClass((id)[NSObject class]) = NSObject meta class // 沿着 NSObject 的继承者链去找根元类 -> 根类 == NSObject meta class 或者 NSObject meta class 的父类的实例
BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [(id)[TestObject class] isKindOfClass:[TestObject class]];
BOOL res4 = [(id)[TestObject class] isMemberOfClass:[TestObject class]];

只有第一个是YES, 剩下的都是NO。 

isKindOfClass: 判断自己的isa 指向的类是否等于传入的类,不等于的话,找自己的继承连中的父类看有没有等于传入的类,有则YES,没有则NO

isMemberOfClass 判断自己的isa 指向的类是否等于传入的类,等于则YES,不等于则NO

源码:

// 类对象,是否是指定的元类的实例
+ (BOOL)isMemberOfClass:(Class)cls {
return object_getClass((id)self) == cls;
} // 实例对象,是否是指定的类的实例
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
} // 类对象,是否是指定的元类cls的实例,或者是cls继承者链中子类的实例
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->super_class) {
if(tcls == cls) return YES;
}
return NO;
}
// 实例对象,是否是指定的类的实例,或者是cls继承者链中子类的实例
-(BOOL)isKindOfClass:(Class)cls {
for(Class tcls = [self class]; tcls; tcls = tcls->super_class) {
if(tcls == cls) return YES;
}
return NO;
}

青山不改,绿水长流,感谢每位佳人支持!

最新文章

  1. jasig CAS 实现单点登录 - java、php客户端登录实现
  2. hping3命令
  3. iOS学习笔记---oc语言第八天
  4. jquery对象和js对象,以及它们的互相转换
  5. 深度分析Java的ClassLoader机制(源码级别)
  6. base查找方法的实现JAVA
  7. Ubuntu升级到14.04
  8. PHP获取文件扩展名的五种方式
  9. HTML表单属性集合
  10. sublime安装、注册、插件
  11. EasyUI easyui-combobox实现数据联动
  12. MySQL InnoDB 索引原理
  13. Android5.0特性ToolBar
  14. DCGAN 代码简单解读
  15. python commands包不支持windows环境与如何在windows下使用的简易方法
  16. TensorFlow从入门到理解(三):你的第一个卷积神经网络(CNN)
  17. 单片机AT和STC区别
  18. Groovy 反射字符串常量方法
  19. python虚拟环境创建
  20. 每个国家对应的语言Locale和国家代码对照表(转)

热门文章

  1. windows中抓取hash小结(下)
  2. 黑马JVM教程——自学笔记(三)
  3. 【springboot】知识点总结
  4. C# 启动 Flask for Python
  5. 2018.7.31-2018.8.2记:关于maven
  6. HuaWeiJava 上机
  7. PyTorch安装及试用 基于Anaconda3
  8. Learning ROS: Ubuntu16.04下kinetic开发环境安装和初体验 Install + Configure + Navigating(look around) + Creating a Package(catkin_create_pkg) + Building a Package(catkin_make) + Understanding Nodes
  9. MySQL的主从复制步骤详解及常见错误解决方法
  10. SpringBoot笔记(2)