一、isa指针
1.1 instance
的isa
指向class
当调用对象方法
时,通过instance
的isa
找到class
,最后找到对象方法
的实现进行调用。
1.2 class
的isa
指向meta-class
当调用类方法
时,通过class
的isa
找到meta-class
,最后找到类方法
的实现进行调用。
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface ZGPerson : NSObject<NSCopying>
{
@public
int _age;
}
@property (nonatomic, assign) int no;
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end
@implementation ZGPerson
- (void)personInstanceMethod {
}
+ (void)personClassMethod {
}
- (id)copyWithZone:(NSZone *)zone {
return nil;
}
@end
@interface ZGStudent : ZGPerson<NSCoding>
{
@public
int _weight;
}
@property (nonatomic, assign) int height;
- (void)studentInstanceMethod;
+ (void)studentClassMethod;
@end
@implementation ZGStudent
- (void)studentInstanceMethod {
}
+ (void)studentClassMethod {
}
- (instancetype)initWithCoder:(NSCoder *)coder {
return nil;
}
- (void)encodeWithCoder:(NSCoder *)coder {
}
@end
二、class对象的superclass指针
2.1 ZGStudent
的instance对象
调用ZGStudent的class
中的对象方法
流程
- 通过 ZGStudent 的 instance对象(
stu
),找到 instance对象(stu
)的isa
- 根据
isa
找到stu
的类对象ZGStudent的class
- 在
ZGStudent的class
中找到对象方法
(studentInstanceMethod)的实现进行调用。
int main(int argc, const char * argv[]) {
@autoreleasepool {
ZGStudent *stu = [[ZGStudent alloc]init];
[stu studentInstanceMethod];
}
return 0;
}
2.2 ZGStudent
的instance对象
调用ZGPerson的class
中的对象方法
流程
- 通过 ZGStudent 的 instance对象(
stu
),找到 instance对象(stu
)的isa
- 根据
isa
找到stu
的类对象ZGStudent的class
- 通过
superclass
找到ZGPerson的class
- 在
ZGPerson的class
中找到对象方法
(personInstanceMethod)的实现进行调用。
int main(int argc, const char * argv[]) {
@autoreleasepool {
ZGStudent *stu = [[ZGStudent alloc]init];
[stu personInstanceMethod];
}
return 0;
}
2.3 ZGStudent
的instance对象
调用NSObject的class
中的对象方法
流程
- 通过 ZGStudent 的 instance对象(
stu
),找到 instance对象(stu
)的isa
- 根据
isa
找到stu
的类对象ZGStudent的class
- 通过
superclass
找到ZGPerson的class
- 通过
superclass
找到NSObject的class
- 在
NSObject的class
中找到对象方法
(init)的实现进行调用。
int main(int argc, const char * argv[]) {
@autoreleasepool {
ZGStudent *stu = [[ZGStudent alloc]init];
[stu init];
}
return 0;
}
三、meta-class对象的superclass指针
3.1 ZGStudent
类调用ZGStudent的meta-class
中的类方法
流程
- 通过
ZGStudent
类,找到ZGStudent
类的isa
- 根据
isa
找到ZGStudent的meta-class
- 在
ZGStudent的meta-class
中找到类方法
(studentClassMethod)的实现进行调用。
int main(int argc, const char * argv[]) {
@autoreleasepool {
[ZGStudent studentClassMethod];
}
return 0;
}
3.2 ZGStudent
类调用ZGPerson的meta-class
中的类方法
流程
- 通过
ZGStudent
类,找到ZGStudent
类的isa
- 根据
isa
找到ZGStudent的meta-class
- 通过
superclass
找到ZGPerson的meta-class
- 在
ZGPerson的meta-class
中找到类方法
(personClassMethod)的实现进行调用。
int main(int argc, const char * argv[]) {
@autoreleasepool {
[ZGStudent personClassMethod];
}
return 0;
}
3.2 ZGStudent
类调用NSObject的meta-class
中的类方法
流程
- 通过
ZGStudent
类,找到ZGStudent
类的isa
- 根据
isa
找到ZGStudent
的meta-class
- 通过
superclass
找到ZGPerson的meta-class
- 通过
superclass
找到NSObject的meta-class
- 在
NSObject的meta-class
中找到类方法
(load)的实现进行调用。
int main(int argc, const char * argv[]) {
@autoreleasepool {
[ZGStudent load];
}
return 0;
}
四、isa、superclass总结
4.1 isa指向
instance
的isa
指向class
class
的isa
指向meta-class
meta-class
的isa
指向基类的meta-class
4.2 superclass指向class
的superclass
指向父类的class
- 如果没有父类,superclass指针为
nil
- 如果没有父类,superclass指针为
meta-class
的superclass
指向父类的meta-class
基类的meta-class
的superclass
指向基类的class
4.3 instance调用对象方法的轨迹
isa
找到class
,方法不存在,就通过superclass
找父类
4.4 class调用类方法的轨迹isa
找meta-class
,方法不存在,就通过superclass
找父类
五、isa指针新变化
从64bit开始,isa需要进行一次位运算,才能计算出真实地址。
六、类调用类方法的调用实现流程
方法调用的实质是给方法调用者发送消息,对象是方法调用者,方法名是消息名称。
如[ZGPerson test]
的实质就是给ZGPerson类
发送一条 test
消息(objc_msgSend
)。下面是通过不同途径ZGPerson类
调用类方法+ (void)test
的实现和调用流程。
6.1 ZGPerson类
类和NSObject类
分别调用自己的类方法
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (Test)
+ (void)test;
@end
NS_ASSUME_NONNULL_END
#import "NSObject+Test.h"
@implementation NSObject (Test)
+ (void)test {
NSLog(@"+[NSObject test] - %p",self);
}
@end
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "NSObject+Test.h"
@interface ZGPerson : NSObject
+ (void)test;
@end
@implementation ZGPerson
+ (void)test {
NSLog(@"+[ZGPerson test] - %p",self);
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"ZGPerson.class---%p", ZGPerson.class);
NSLog(@"NSObject.class---%p", NSObject.class);
[ZGPerson test];
[NSObject test];
}
return 0;
}
调用流程:
- 通过
ZGPerson类
的isa
找到ZGPerson的meta-class
- 到
ZGPerson的meta-class
中查找对应的类方法+ (void)test
,找到后调用。
6.2 去掉ZGPerson
类的类方法+(void)test
实现
//+ (void)test {
// NSLog(@"+[ZGPerson test] - %p",self);
//}
调用流程:
- 通过
ZGPerson类
的isa
找到ZGPerson的meta-class
ZGPerson的meta-class
中没有类方法+ (void)test
,通过ZGPerson的meta-class
的superclass
到它的父类NSObject的meta-class
中查找类方法+ (void)test
,找到后调用。
6.3 去掉NSObject+Test
类的类方法+(void)test
实现,改为对象方法- (void)test
#import "NSObject+Test.h"
@implementation NSObject (Test)
//+ (void)test {
// NSLog(@"+[NSObject test] - %p",self);
//}
- (void)test {
NSLog(@"- [NSObject test] - %p",self);
}
@end
调用流程:
- 通过
ZGPerson类
的isa
到ZGPerson的meta-class
中查找对应的类方法+ (void)test
ZGPerson的meta-class
中没有类方法+ (void)test
,通过ZGPerson的meta-class
的superclass
到它的父类NSObject的meta-class
中查找类方法+ (void)test
NSObject的meta-class
中没有类方法+ (void)test
,通过NSObject的meta-class
的isa
,到NSObject的class
中查找- (void)test
方法,有该方法的实现,调用成功。
七、isa指向的验证
前文我们提到,通过isa
对实例对象和类对象建立联系。可以简单认为,通过实例对象的isa
找到类对象class
,类对象class
的isa
找到元类对象meta-class
。
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface ZGPerson : NSObject<NSCopying>
{
@public
int _age;
}
@property (nonatomic, assign) int no;
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end
@implementation ZGPerson
- (void)personInstanceMethod {
}
+ (void)personClassMethod {
}
- (id)copyWithZone:(NSZone *)zone {
return nil;
}
@end
@interface ZGStudent : ZGPerson<NSCoding>
{
@public
int _weight;
}
@property (nonatomic, assign) int height;
- (void)studentInstanceMethod;
+ (void)studentClassMethod;
@end
@implementation ZGStudent
- (void)studentInstanceMethod {
}
+ (void)studentClassMethod {
}
- (instancetype)initWithCoder:(NSCoder *)coder {
return nil;
}
- (void)encodeWithCoder:(NSCoder *)coder {
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
ZGPerson *person = [ZGPerson new];
Class personClass = ZGPerson.class;
Class personMetaClass = object_getClass(personClass);
NSLog(@"\n person:%p\n personClass:%p\n personMetaClass:%p\n",person,personClass,personMetaClass);
}
return 0;
}
前文我们说过,实例对象的isa
指向类对象,按理来说,person
的isa
的地址应该和person.class
类对象地址是一致的,但我们发现这里的内存地址并不一样。
其实在arm64架构
之前,isa
就是一个普通的指针,存储着Class、MetaClass
对象的内存地址
。从arm64架构
开始,对isa
进行了优化,变成了一个共用体(union
)结构,还使用位域
来存储更多信息。
从64bit
开始,isa
需要进行一次位运算
,才能计算出真实地址。
因为当前项目是Mac项目,我们调用_ _X86_64_ _
架构的ISA_MASK
,对应的值是0x00007ffffffffff8ULL
。
isa & ISA_MASK
就和我们的类对象的地址对应上了。
Instance实例对象的isa & ISA_MASK地址 = class类对象地址
接下来,同样的步骤,我们来获取下元类对象的地址。
通过前文查看源码,我们了解到,我们的class
内部其实是typedef* struct objc_class *Class
结构,是一个结构体。那么我们写一个内部结构一模一样的结构体,指向当前的元类对象,那么我们是不是就能拿到元类对象的isa
呢?
经过简化,我们得到一个这样的结构体,代码如下:
struct zg_objc_class {
Class isa;
Class superclass;
};
class类对象的isa & ISA_MASK地址 = meta-class元类对象地址
八、objc4源码下载
下载地址:opensource.apple.com/tarballs/ob…
class
、meta-class
对象的本质结构都是struct objc_class
。
九、窥探struct objc_class的结构
objc_class:
objc_object:
isa_t:
class_rw_t:
class_ro_t:
最终我们得到了objc_class
的内部结构,如下图:
下面我们来验证一下这个结构能否拿取到对应的数据,拿到对应的数据,说明我们这个结构是正确的。 首先引入文件MJClassInfo.h,
//
// MJClassInfo.h
// TestClass
//
// Created by MJ Lee on 2018/3/8.
// Copyright © 2018年 MJ Lee. All rights reserved.
//
#import <Foundation/Foundation.h>
#ifndef MJClassInfo_h
#define MJClassInfo_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 mj_objc_object {
void *isa;
};
/* 类对象 */
struct mj_objc_class : mj_objc_object {
Class superclass;
cache_t cache;
class_data_bits_t bits;
public:
class_rw_t* data() {
return bits.data();
}
mj_objc_class* metaClass() {
return (mj_objc_class *)((long long)isa & ISA_MASK);
}
};
#endif /* MJClassInfo_h */
因为MJClassInfo.h文件是C++编写的,所以在这里需要修改一下main.m为main.mm,避免编译报错。
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "MJClassInfo.h"
@interface ZGPerson : NSObject<NSCopying>
{
@public
int _age;
int _name;
}
@property (nonatomic, assign) int no;
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end
@implementation ZGPerson
- (void)personInstanceMethod {
}
+ (void)personClassMethod {
}
- (id)copyWithZone:(NSZone *)zone {
return nil;
}
@end
@interface ZGStudent : ZGPerson<NSCoding>
{
@public
int _weight;
}
@property (nonatomic, assign) int height;
- (void)studentInstanceMethod;
+ (void)studentClassMethod;
@end
@implementation ZGStudent
- (void)studentInstanceMethod {
}
+ (void)studentClassMethod {
}
- (instancetype)initWithCoder:(NSCoder *)coder {
return nil;
}
- (void)encodeWithCoder:(NSCoder *)coder {
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
struct mj_objc_class *studentClass = (__bridge struct mj_objc_class *)(ZGStudent.class);
struct mj_objc_class *personClass = (__bridge struct mj_objc_class *)(ZGPerson.class);
class_rw_t *studentClassData = studentClass->data();
class_rw_t *personClassData = personClass->data();
NSLog(@"theEnd");
}
return 0;
}
获取结果:
studentClass
结构:
personClass
结构:
studentClassData
结构:
personClassData
结构: