先附上经典图, 表示敬畏
isa的走位
实例对象(Instance of Subclass
)的isa
指向 类(class)
类对象(class) isa
指向元类(Meta class)
元类(Meta class
)的isa
指向根元类(Root metal class
元类(Root metal class)
的isa
指向它自己本身,形成闭环,这里的根元类
就是NSObject
superclass(继承关系)走位
类(subClass
) 继承自父类(superClass)
父类(superClass)
继承自根类(RootClass )
,此时的根类
是指NSObject
根类
继承自nil
,所以根类
即NSObject
可以理解为万物起源子类
的元类(metal SubClass)
继承自父类
的元类(metal SuperClass)
父类
的元类(metal SuperClass )
继承自根元类(Root metal Class
根元类(Root metal Class)
继承于根类(Root class )
,此时的根类
是指NSObject
- 【注意】
实例对象
之间没有
继承关系,类
之间有继承关系
*
分析
LGPerson
@interface LGPerson : NSObject
+ (void)sayHello;
- (void)say666;
@end
#import "LGPerson.h"
@interface LGPerson ()
@property (nonatomic, copy) NSString *name;
@end
@implementation LGPerson{
NSString *_hobby;
}
+ (void)sayHello{
NSLog(@"sayHello");
}
- (void)say666{
NSLog(@"say666");
}
@end
LGTeacher 继承LGPerson
#import "LGPerson.h"
@interface LGTeacher : LGPerson
@end
#import "LGTeacher.h"
@implementation LGTeacher
@end
LGPerson *person = [LGPerson alloc];
LGTeacher *teacher = [LGTeacher alloc];
NSLog(@"Hello, Person! %@",person);
NSLog(@"Hello, Teacher! %@",teacher);
p/x
: 打印person首地址
x/4gx
:查看person内存情况: 第一个为isa指针地址
指针地址
&0x00007ffffffffff8ULL
: 获取类信息
isa走位
person -> LGPerson ->LGPerson(元类)->NSObject(根元类)->NSObject
类结构分析
LGPerson继承至NSObject
@interface NSObject {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
NSObject
的底层编译是NSObject_IMPL
结构体,
其中 Class
是isa
指针的类型,是由objc_class
定义的类型,
而objc_class
是一个结构体。在iOS中,所有的Class
都是以 objc_class
为模板创建的`
struct NSObject_IMPL {
Class isa;
};
typedef struct objc_class *Class;
查看源码已经被废除
不过可以根据最后一行注释(/* Use
Class
instead of struct objc_class *
*/
)找到目前所用的class
【问题】objc_class 与 objc_object 有什么关系?
通过上述的源码查找以及main.cpp中底层编译源码,有以下几点说明:
结构体类型
objc_class
继承自objc_object
类型,其中objc_object
也是一个结构体,且有一个isa
属性,所以objc_class
也拥有了isa
属性mian.cpp底层编译文件中,
NSObject
中的isa
在底层是由Class
定义的,其中class
的底层编码来自objc_class
类型,所以NSObject
也拥有了isa
属性NSObject
是一个类,用它初始化一个实例对象objc
,objc 满足objc_object
的特性(即有isa属性),主要是因为isa
是由NSObject
从objc_class
继承过来的,而objc_class
继承自objc_object
,objc_object
有isa
属性。所以对象
都有一个isa
,isa表示指向
,来自于当前的objc_object
objc_object(结构体)
是 当前的根对象
,所有的对象
都有这样一个特性objc_object
,即拥有isa属性
【百度面试题】objc_object 与 对象的关系
所有的
对象
都是以objc_object
为模板继承
过来的所有的对象 是 来自
NSObject
(OC) ,但是真正到底层的 是一个objc_object(C/C++)
的结构体类型
【总结】 objc_object
与 对象
的关系
是 继承
关系
总结
所有的
对象
+类
+元类
都有isa
属性所有的
对象
都是由objc_object
继承来的-
简单概括就是
万物皆对象
,万物皆来源于objc_object
,有以下两点结论:所有以
objc_object
为模板 创建的对象
,都有isa
属性所有以
objc_class
为模板,创建的类
,都有isa
属性
-
在结构层面可以通俗的理解为
上层OC
与底层
的对接
:-
下层
是通过结构体
定义的模板
,例如objc_class、objc_object
-
上层
是通过底层的模板创建
的 一些类型,例如CJLPerson
-
objc_class、objc_object、isa、object、NSObject
等的整体的关系,如下图所示
到底类中有哪些信息呢?
根据前文提及的objc_class 的新版定义(objc4-781版本)如下,有以下几个属性
struct objc_class : objc_object {
// Class ISA; //8字节
Class superclass; //Class 类型 8字节
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
//....方法部分省略,未贴出
}
可以通过地址偏移获取bits里面的类信息, 首先我们还需要知道地址的偏移量
isa: objc继承至objc_object, 所以也包含一个isa指针,继承自objc_object的isa,占 8字节
superclass 属性:Class类型,Class是由objc_object定义的,是一个指针,占8字节
cache属性:简单从类型class_data_bits_t目前无法得知,而class_data_bits_t是一个结构体类型,结构体的内存大小需要根据内部的属性来确定,而结构体指针才是8字节
bits属性:只有首地址经过上面3个属性的内存大小总和的平移,才能获取到bits
struct cache_t {
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
explicit_atomic _buckets; // 是一个结构体指针类型,占8字节
explicit_atomic _mask; //是mask_t 类型,而 mask_t 是 unsigned int 的别名,占4字节
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
explicit_atomic _maskAndBuckets; //是指针,占8字节
mask_t _mask_unused; //是mask_t 类型,而 mask_t 是 uint32_t 类型定义的别名,占4字节
#if __LP64__
uint16_t _flags; //是uint16_t类型,uint16_t是 unsigned short 的别名,占 2个字节
#endif
uint16_t _occupied; //是uint16_t类型,uint16_t是 unsigned short 的别名,占 2个字节
获取bits
所以有上述计算可知,想要获取bits的中的内容,只需通过类的首地址平移32字节即可
以下是通过lldb命令调试的过程
也可以打印属性列表
以及存在ro里面的ivars