以下源码均来自 objc runtime 723
目录
一个简单的例子
@interface TestObject : NSObject
@end
这里,我们构建了一个非常简单的 OC 类 —— 仅仅继承了 NSObject
,没有任何的属性、方法等。
NSObject
TestObject
这个类在 Runtime 中到底是如何表达的?我们先从 NSObject
看起:
@protocol NSObject
- (BOOL)isEqual:(id)object;
//...
- (id)performSelector:(SEL)aSelector;
//...
- (BOOL)isKindOfClass:(Class)aClass;
//...一大堆方法
@property (readonly, copy) NSString *description;
@end
@interface NSObject <NSObject> {
/*
这里的`OBJC_ISA_AVAILABILITY`比较有意思,在`objc-api.h`文件中找到了其定义,其中注释说道`isa`
会在未来废弃掉。看来苹果有过大改 Runtime 机制的想法,但最终放弃了。印象中因此才有了 Swift 的诞
生
*/
Class isa OBJC_ISA_AVAILABILITY;
}
//...一大堆方法
@end
可以看到,NSObject
类是一个遵循 NSObject
协议的大基类。NSObject
协议中包含了如 isEqual:
, isKindOfClass:
和 performSelector:
等抽象方法。而 NSObject
类中包含了对 NSObject
协议方法的默认实现,以及如 load
, init
和 copy
等 NSObject
类独有的方法。这些方法大多都是直接调用 Runtime 的私有 API 实现。例如经常用到的 respondsToSelector:
方 法实现:
- (BOOL)respondsToSelector:(SEL)sel {
if (!sel) return NO;
return class_respondsToSelector_inst([self class], sel, self); //此方法暴露在`objc-private.h`头文件中
}
需要注意 NSObject
类中也有许多需要子类手动实现的抽象接口,例如:
// 子类需要重写`description`方法以返回正确的描述信息
- (NSString *)description {
return nil;
}
id
提到了 NSObject
则不得不提在 OC 中非常常见的 id
类型 —— id
的定义为一个指向 objc_object
的指针:
typedef struct objc_object *id;
obj_object
的定义大致如下:
struct objc_object {
private:
isa_t isa;
public:
//...一大堆方法
private:
//...一大堆方法
isa_t
可以看到 objc_object
中也有个 isa
指针,但与 NSObject
不同的是,这里的 isa
指针为 isa_t
类型。我们查看其源码发现,isa_t
为一个 union
联合体。(关于 union
的知识可以参考 联合体(union)的使用方法及其本质)
union isa_t
{
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits; // `uintptr_t`为unsigned long类型
}
除去上面的基础数据结构外,isa_t
在不同架构下会有不同的附加数据结构。例如在 arm64 环境下有 64 位的附加数据:
struct {
uintptr_t nonpointer : 1; // 是否开启指针优化,tagged pointer 相关
uintptr_t has_assoc : 1; // 是否有associated object
uintptr_t has_cxx_dtor : 1; // 是否有析构器
uintptr_t shiftcls : 33; // 类的指针,MACH_VM_MAX_ADDRESS 0x1000000000
uintptr_t magic : 6; // 固定为0xd2
uintptr_t weakly_referenced : 1; // 对象是否有弱引用
uintptr_t deallocating : 1; // 对象是否正在析构
uintptr_t has_sidetable_rc : 1; // 对象的引用计数是否过大无法存储在isa中
uintptr_t extra_rc : 19; // 对象的(引用计数-1),必须为最高有效位
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
};
这里用图片的方式更直观的描述下 isa_t
在 arm64 架构下内存中的存储:

isa_t
这里非常有意思的是 Tagged Pointer,在 WWDC 2013 的 Advances in Objective-C 中提到了 Runtime 中对于 Tagged Pointer 的应用。Tagged Pointer 主要应用于对指针内存的优化上。关于 Tagged Pointer 的问题,巧哥的一篇 深入理解Tagged Pointer 作了深入解释。这里只简单介绍一下。
在内存存储中,指针的的地址是内存对齐,且与系统架构相关的。例如在 64 位的机器上,一个对象指针为 64 位。而指针中只有 60 位是真正的对象指针,剩余的四个低位主要为了内存对齐。
例如在 Objective-C 中,一个整数类型的 NSNumber
对象在 32 位系统中占用的内存大小为 4 个字节,但迁移到 64 为系统后,其所占的内存大小会翻倍,由 4 个字节变为 8 个字节。
苹果引入了 Tagged Pointed 技术后,对于一些如 NSNumber
、NSDate
等长度不变且内存占用较小的对象,优化了其指针内存性能。通过对指针最低位设置为 1
来标明 Tagged Pointer,这时指针会被分成两部分 —— 保存数据的部分和附加标记的部分(例如引用计数等)。
Class
在 NSObject
类的定义中,可以看到其只有 Class
类型一个公开的成员变量 isa
。Class
的定义十分简单:一个指向 objc_class
结构体的指针:
typedef struct objc_class *Class;
以下源码均来自 objc runtime 723
目录
一个简单的例子
@interface TestObject : NSObject
@end
这里,我们构建了一个非常简单的 OC 类 —— 仅仅继承了 NSObject
,没有任何的属性、方法等。
NSObject
TestObject
这个类在 Runtime 中到底是如何表达的?我们先从 NSObject
看起:
@protocol NSObject
- (BOOL)isEqual:(id)object;
//...
- (id)performSelector:(SEL)aSelector;
//...
- (BOOL)isKindOfClass:(Class)aClass;
//...一大堆方法
@property (readonly, copy) NSString *description;
@end
@interface NSObject <NSObject> {
/*
这里的`OBJC_ISA_AVAILABILITY`比较有意思,在`objc-api.h`文件中找到了其定义,其中注释说道`isa`
会在未来废弃掉。看来苹果有过大改 Runtime 机制的想法,但最终放弃了。印象中因此才有了 Swift 的诞
生
*/
Class isa OBJC_ISA_AVAILABILITY;
}
//...一大堆方法
@end
可以看到,NSObject
类是一个遵循 NSObject
协议的大基类。NSObject
协议中包含了如 isEqual:
, isKindOfClass:
和 performSelector:
等抽象方法。而 NSObject
类中包含了对 NSObject
协议方法的默认实现,以及如 load
, init
和 copy
等 NSObject
类独有的方法。这些方法大多都是直接调用 Runtime 的私有 API 实现。例如经常用到的 respondsToSelector:
方 法实现:
- (BOOL)respondsToSelector:(SEL)sel {
if (!sel) return NO;
return class_respondsToSelector_inst([self class], sel, self); //此方法暴露在`objc-private.h`头文件中
}
需要注意 NSObject
类中也有许多需要子类手动实现的抽象接口,例如:
// 子类需要重写`description`方法以返回正确的描述信息
- (NSString *)description {
return nil;
}
id
提到了 NSObject
则不得不提在 OC 中非常常见的 id
类型 —— id
的定义为一个指向 objc_object
的指针:
typedef struct objc_object *id;
obj_object
的定义大致如下:
struct objc_object {
private:
isa_t isa;
public:
//...一大堆方法
private:
//...一大堆方法
isa_t
可以看到 objc_object
中也有个 isa
指针,但与 NSObject
不同的是,这里的 isa
指针为 isa_t
类型。我们查看其源码发现,isa_t
为一个 union
联合体。(关于 union
的知识可以参考 联合体(union)的使用方法及其本质)
union isa_t
{
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits; // `uintptr_t`为unsigned long类型
}
除去上面的基础数据结构外,isa_t
在不同架构下会有不同的附加数据结构。例如在 arm64 环境下有 64 位的附加数据:
struct {
uintptr_t nonpointer : 1; // 是否开启指针优化,tagged pointer 相关
uintptr_t has_assoc : 1; // 是否有associated object
uintptr_t has_cxx_dtor : 1; // 是否有析构器
uintptr_t shiftcls : 33; // 类的指针,MACH_VM_MAX_ADDRESS 0x1000000000
uintptr_t magic : 6; // 固定为0xd2
uintptr_t weakly_referenced : 1; // 对象是否有弱引用
uintptr_t deallocating : 1; // 对象是否正在析构
uintptr_t has_sidetable_rc : 1; // 对象的引用计数是否过大无法存储在isa中
uintptr_t extra_rc : 19; // 对象的(引用计数-1),必须为最高有效位
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
};
这里用图片的方式更直观的描述下 isa_t
在 arm64 架构下内存中的存储:

isa_t
这里非常有意思的是 Tagged Pointer,在 WWDC 2013 的 Advances in Objective-C 中提到了 Runtime 中对于 Tagged Pointer 的应用。Tagged Pointer 主要应用于对指针内存的优化上。关于 Tagged Pointer 的问题,巧哥的一篇 深入理解Tagged Pointer 作了深入解释。这里只简单介绍一下。
在内存存储中,指针的的地址是内存对齐,且与系统架构相关的。例如在 64 位的机器上,一个对象指针为 64 位。而指针中只有 60 位是真正的对象指针,剩余的四个低位主要为了内存对齐。
例如在 Objective-C 中,一个整数类型的 NSNumber
对象在 32 位系统中占用的内存大小为 4 个字节,但迁移到 64 为系统后,其所占的内存大小会翻倍,由 4 个字节变为 8 个字节。
苹果引入了 Tagged Pointed 技术后,对于一些如 NSNumber
、NSDate
等长度不变且内存占用较小的对象,优化了其指针内存性能。通过对指针最低位设置为 1
来标明 Tagged Pointer,这时指针会被分成两部分 —— 保存数据的部分和附加标记的部分(例如引用计数等)。
Class
在 NSObject
类的定义中,可以看到其只有 Class
类型一个公开的成员变量 isa
。Class
的定义十分简单:一个指向 objc_class
结构体的指针:
typedef struct objc_class *Class;
以下源码均来自 objc runtime 723
目录
一个简单的例子
@interface TestObject : NSObject
@end
这里,我们构建了一个非常简单的 OC 类 —— 仅仅继承了 NSObject
,没有任何的属性、方法等。
NSObject
TestObject
这个类在 Runtime 中到底是如何表达的?我们先从 NSObject
看起:
@protocol NSObject
- (BOOL)isEqual:(id)object;
//...
- (id)performSelector:(SEL)aSelector;
//...
- (BOOL)isKindOfClass:(Class)aClass;
//...一大堆方法
@property (readonly, copy) NSString *description;
@end
@interface NSObject <NSObject> {
/*
这里的`OBJC_ISA_AVAILABILITY`比较有意思,在`objc-api.h`文件中找到了其定义,其中注释说道`isa`
会在未来废弃掉。看来苹果有过大改 Runtime 机制的想法,但最终放弃了。印象中因此才有了 Swift 的诞
生
*/
Class isa OBJC_ISA_AVAILABILITY;
}
//...一大堆方法
@end
可以看到,NSObject
类是一个遵循 NSObject
协议的大基类。NSObject
协议中包含了如 isEqual:
, isKindOfClass:
和 performSelector:
等抽象方法。而 NSObject
类中包含了对 NSObject
协议方法的默认实现,以及如 load
, init
和 copy
等 NSObject
类独有的方法。这些方法大多都是直接调用 Runtime 的私有 API 实现。例如经常用到的 respondsToSelector:
方 法实现:
- (BOOL)respondsToSelector:(SEL)sel {
if (!sel) return NO;
return class_respondsToSelector_inst([self class], sel, self); //此方法暴露在`objc-private.h`头文件中
}
需要注意 NSObject
类中也有许多需要子类手动实现的抽象接口,例如:
// 子类需要重写`description`方法以返回正确的描述信息
- (NSString *)description {
return nil;
}
id
提到了 NSObject
则不得不提在 OC 中非常常见的 id
类型 —— id
的定义为一个指向 objc_object
的指针:
typedef struct objc_object *id;
obj_object
的定义大致如下:
struct objc_object {
private:
isa_t isa;
public:
//...一大堆方法
private:
//...一大堆方法
isa_t
可以看到 objc_object
中也有个 isa
指针,但与 NSObject
不同的是,这里的 isa
指针为 isa_t
类型。我们查看其源码发现,isa_t
为一个 union
联合体。(关于 union
的知识可以参考 联合体(union)的使用方法及其本质)
union isa_t
{
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits; // `uintptr_t`为unsigned long类型
}
除去上面的基础数据结构外,isa_t
在不同架构下会有不同的附加数据结构。例如在 arm64 环境下有 64 位的附加数据:
struct {
uintptr_t nonpointer : 1; // 是否开启指针优化,tagged pointer 相关
uintptr_t has_assoc : 1; // 是否有associated object
uintptr_t has_cxx_dtor : 1; // 是否有析构器
uintptr_t shiftcls : 33; // 类的指针,MACH_VM_MAX_ADDRESS 0x1000000000
uintptr_t magic : 6; // 固定为0xd2
uintptr_t weakly_referenced : 1; // 对象是否有弱引用
uintptr_t deallocating : 1; // 对象是否正在析构
uintptr_t has_sidetable_rc : 1; // 对象的引用计数是否过大无法存储在isa中
uintptr_t extra_rc : 19; // 对象的(引用计数-1),必须为最高有效位
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
};
这里用图片的方式更直观的描述下 isa_t
在 arm64 架构下内存中的存储:

isa_t
这里非常有意思的是 Tagged Pointer,在 WWDC 2013 的 Advances in Objective-C 中提到了 Runtime 中对于 Tagged Pointer 的应用。Tagged Pointer 主要应用于对指针内存的优化上。关于 Tagged Pointer 的问题,巧哥的一篇 深入理解Tagged Pointer 作了深入解释。这里只简单介绍一下。
在内存存储中,指针的的地址是内存对齐,且与系统架构相关的。例如在 64 位的机器上,一个对象指针为 64 位。而指针中只有 60 位是真正的对象指针,剩余的四个低位主要为了内存对齐。
例如在 Objective-C 中,一个整数类型的 NSNumber
对象在 32 位系统中占用的内存大小为 4 个字节,但迁移到 64 为系统后,其所占的内存大小会翻倍,由 4 个字节变为 8 个字节。
苹果引入了 Tagged Pointed 技术后,对于一些如 NSNumber
、NSDate
等长度不变且内存占用较小的对象,优化了其指针内存性能。通过对指针最低位设置为 1
来标明 Tagged Pointer,这时指针会被分成两部分 —— 保存数据的部分和附加标记的部分(例如引用计数等)。
Class
在 NSObject
类的定义中,可以看到其只有 Class
类型一个公开的成员变量 isa
。Class
的定义十分简单:一个指向 objc_class
结构体的指针:
typedef struct objc_class *Class;