OC中runtime.h包含了OC中使用的一系列的底层C语言API声明
类的结构
typedef struct objc_class *Class; // 此声明在objc.h文件中
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY; 指向类
#if !__OBJC2__
Class _Nullable super_class 指向父类
const char * _Nonnull name 类名
long version 版本相关信息,默认为0
long info 提供运行期使用的标示符
long instance_size 当前类实例变量的大小
struct objc_ivar_list * _Nullable ivars 成员变量列表
struct objc_method_list * _Nullable * _Nullable methodLists 类中的方法相关信息列表
struct objc_cache * _Nonnull cache 调用过的方法的相关信息列表
struct objc_protocol_list * _Nullable protocols 遵循的协议信息列表
#endif
} OBJC2_UNAVAILABLE;
可以看出:
1.Class
是指向struct objc_class
结构体类型的结构体指针
2.Class
内部包含了指向对象类的isa
指针和指向父类的super_class指针
3.ivars是指向objc_ivar_list结构体的指针,objc_ivar_list结构如下:
struct objc_ivar {
char * _Nullable ivar_name 成员变量名
char * _Nullable ivar_type 成员变量类型
int ivar_offset 指针偏移量
#ifdef __LP64__
int space 占用的内存空间
#endif
}
struct objc_ivar_list {
int ivar_count
#ifdef __LP64__
int space
#endif
/* variable length structure */
struct objc_ivar ivar_list[1]
}
很显然ivars是个链表,内部包含了指向类中成员变量名称和成员变量类型的节点。
4.methodLists
也是链表,存储类中的方法相关信息,objc_method_list
的结构在runtime.h中也能找到,这里不在展示。
5.cache
链表:存储曾经调用过的方法的相关信息,这样将常用方法存到cache中,可以提高方法的查找效率。
6.protocols
链表:存储当前类(包括父类)遵守的协议的相关信息。
底层函数
// 返回对象的副本
id object_copy(id obj, size_t size);
// 释放对象占用的内存
id object_dispose(id obj);
// 返回对象的类
Class object_getClass(id obj);
// 设置对象的类型,并返回类型
Class object_setClass(id obj, Class cls);
// 判断对象是否是类或元类
BOOL object_isClass(id obj);
// 获取对象实例变量的值
id object_getIvar(id obj, Ivar ivar);
// 设置对象实例变量的值
void object_setIvar(id obj, Ivar ivar, id value);
void object_setIvarWithStrongDefault(id obj, Ivar ivar, id value);
// 修改类实例中实例变量的值
Ivar object_setInstanceVariableWithStrongDefault(id obj, const char *name
Ivar object_setInstanceVariable(id obj, const char *name, void *value);, void *value);
// 获取指定名称的类,指定类名不存在会调用类回调处理
Class objc_getClass(const char *name);
// 返回指定的元类
Class objc_getMetaClass(const char *name);
// 返回指定的类
Class objc_lookUpClass(const char *name)
Class objc_getRequiredClass(const char *name);
// 返回已注册的类定义的列表
int objc_getClassList(Class *buffer, int bufferCount);
// 创建并返回一个指向所有已注册类的列表指针
Class *objc_copyClassList(unsigned int *outCount);
// 返回类名
const char *class_getName(Class cls)
// 是否是元类
BOOL class_isMetaClass(Class cls);
// 返回类的父类
Class class_getSuperclass(Class cls);
// 给类指定一个父类,并返回旧的父类
Class class_setSuperclass(Class cls, Class newSuper);
// 返回类的版本号
OBJC_EXPORT int class_getVersion(Class cls);
// 设置类版本号
void class_setVersion(Class cls, int version);
// 返回实例类的大小
size_t class_getInstanceSize(Class cls);
// 返回类中指定名称实例变量的信息
Ivar class_getInstanceVariable(Class cls, const char *name);
// 返回类中指定名称实例成员变量的信息
Ivar class_getInstanceVariable(Class cls, const char *name);
// 返回类指定名称变量的信息
Ivar class_getClassVariable(Class cls, const char *name);
// 返回整个成员变量列表
Ivar *class_copyIvarList(Class cls, unsigned int *outCount);
// 返回类中指定实例方法
Method class_getInstanceMethod(Class cls, SEL name);
// 返回类中指定的类方法
Method class_getClassMethod(Class cls, SEL name);
// 返回类中所有方法的列表
Method *class_copyMethodList(Class cls, unsigned int *outCount);
// 返回类方法的入口指针
IMP class_getMethodImplementation(Class cls, SEL name);
// 返回类方法实现的指针
IMP class_getMethodImplementation_stret(Class cls, SEL name);
/* An opaque type that represents a method in a class definition.
Method是objc_method结构体类型指针
objc_method结构体,包含了方法方法的名称,参数类型以及方法实现的入口指针(IMP)
*/
typedef struct objc_method *Method;
struct objc_method {
SEL method_name
char * method_types
IMP method_imp
}
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
#endif
// 类的实例是否响应指定的方法
BOOL class_respondsToSelector(Class cls, SEL sel);
// 返回类是否实现指定的协议
BOOL class_conformsToProtocol(Class cls, Protocol *protocol);
// 返回这个类所遵循的协议
Protocol ** class_copyProtocolList(Class cls, unsigned int *outCount);
// 返回类中指定名称的属性
objc_property_t class_getProperty(Class cls, const char * name)
// 返回类中声明的属性
objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
注意:class_copyPropertyList 和 class_copyIvarList 是不同的,前者获取的只是类中声明的属性变量,后者则是获取类中的实例变量
@interface Person : NSObject
{
NSString *_name;
}
@property (nonatomic, assign) int sex;
@property (nonatomic, assign) int age;
@property (nonatomic, copy) NSString *tele;
@end
---------------------------------------------------------------------------------------------
- (void)viewDidLoad {
[super viewDidLoad];
uint count = 0;
Ivar *ivarList = class_copyIvarList(objc_getClass("Person"), &count);
for (int i = 0; i < count; i++) {
NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivarList[i])];
NSLog(@"ivarName:%@",ivarName);
}
NSLog(@"---------------------------");
uint count2= 0;
objc_property_t *properties = class_copyPropertyList(objc_getClass("Person"), &count2);
for (int i = 0; i < count2; i++) {
NSString *propertyName = [NSString stringWithUTF8String:property_getName(properties[i])];
NSLog(@"propertyName:%@",propertyName);
}
--------------------------------------console------------------------------------------------
[1037:59125] ivarName:_name
[1037:59125] ivarName:_sex
[1037:59125] ivarName:_age
[1037:59125] ivarName:_tele
---------------------------
[1037:59125] propertyName:sex
[1037:59125] propertyName:age
[1037:59125] propertyName:tele
// 获取类中强引用成员变量的布局
const uint8_t *class_getIvarLayout(Class cls);
// 设置变量布局
void class_setIvarLayout(Class cls, const uint8_t *layout);
// 获取类中弱引用成员变量的布局
uint8_t *class_getWeakIvarLayout(Class cls);
// 设置弱属性的变量布局
void class_setWeakIvarLayout(Class cls, const uint8_t *layout)
ivar 的修饰信息在Class 的 Ivar Layout 中,具体看objc-runtime-new.h,OC Class Ivar Layout 探索
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout; // 存储 strong 的 ivar
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout; // 存储 weak 的 ivar
property_list_t *baseProperties;
method_list_t *baseMethods() const {
return baseMethodList;
}
};
// 为类添加新的方法
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
// 方法存在时替代方法的实现,方法不存在时相当于class_addMethod
IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char * types)
// 为类添加实例变量
class_addIvar(Class cls, const char * name, size_t size, uint8_t alignment, const char * types)
// 为类添加新的协议
class_addProtocol(Class cls, Protocol *protocol) ;
// 添加属性
class_addProperty(Class cls, const char *name,const objc_property_attribute_t *attributes, unsigned int attributeCount)
// 替换属性
void class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount);
// 通过CoreFoundation's自由连接。不能自己调用此方法
Class objc_getFutureClass(const char *name);
// 创建类实例
id class_createInstance(Class cls, size_t extraBytes);
// 在指定位置创建类实例
id objc_constructInstance(Class cls, void *bytes);
// 在不释放内存的情况下销毁类的实例,并删除此实例可能具有的任何关联引用。
void *objc_destructInstance(id obj)
// 创建新的类
Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes);
// 注册由objc_allocateClassPair创建的类
void objc_registerClassPair(Class cls)
以上两个函数一起创建一个新的类
例如创建一个新的类Person,继承与NSObject:
Class newCls = objc_allocateClassPair([NSObject class], "Person", 0);
objc_registerClassPair(newCls);
// 用于KVO观察者模式。 不能自己调用此方法
Class objc_duplicateClass(Class original, const char * name, size_t extraBytes)
// 销毁一个类及其相关联的类
void objc_disposeClassPair(Class cls);
// 返回方法的名称
SEL method_getName(Method m);
// 返回一个函数指针
IMP method_getImplementation(Method m)
上面这两个方法是不一样。
前者:返回的SEL是一个objc_selector结构体类型指针:
/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;
Mac OSX仅仅将SEL映射为C字符串所以相同的方法名具有相同的SEL编号,即使它们属于不同的类
后者:返回的IMP本质上是一个函数指针的别名,直接指向函数在内存中的入口实现地址,而无需通过消息传递定位
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
#endif
// 返回方法接收参数的个数
注意所有函数都有两个隐藏的参数SEL和_cmd,所以参数个数会多+2
unsigned int method_getNumberOfArguments(Method m);
// 返回描述方法返回类型的字符串
char *method_copyReturnType(Method m)
// 返回描述方法单个参数类型的字符串
char *method_copyArgumentType(Method m, unsigned int index)
// 通过引用返回描述方法的返回类型
void method_getReturnType(Method m, char *dst, size_t dst_len)
// 通过引用返回描述方法的单个参数类型
void method_getArgumentType(Method m, unsigned int index, char *dst, size_t dst_len);
// 返回指定方法的结构描述
struct objc_method_description *method_getDescription(Method m);
struct objc_method_description {
SEL name; 方法名
char *types; 参数类型
};
具体参考:Type Encodings
// 设置方法的入口实现地址
IMP method_setImplementation(Method m, IMP imp);
// 交换两个方法的实现入口地址
void method_exchangeImplementations(Method m1, Method m2);
ivar
// 返回实例变量的名称
const char *ivar_getName(Ivar v);
// 返回实例变量类型字符串
const char *ivar_getTypeEncoding(Ivar v);
// 返回实例变量的偏移量
ptrdiff_t ivar_getOffset(Ivar v);
property
// 返回属性名称
const char *property_getName(objc_property_t property);
// 返回属性的属性字符串
const char *property_getAttributes(objc_property_t property);
// 返回属性的属性数组
objc_property_attribute_t *property_copyAttributeList(objc_property_t property, unsigned int *outCount);
// 返回指定属性名称的属性的值
char *property_copyAttributeValue(objc_property_t property, const char *attributeName);
protocol
// 返回指定名称的协议
Protocol *objc_getProtocol(const char *name);
// 返回runtime已知的所有协议的数组
Protocol * __unsafe_unretained *objc_copyProtocolList(unsigned int *outCount);
// 判断一个协议是否遵循了另一个协议
BOOL protocol_conformsToProtocol(Protocol *proto, Protocol *other);
// 判断两个协议是否相等
BOOL protocol_isEqual(Protocol *proto, Protocol *other);
// 返回协议的名称
const char *protocol_getName(Protocol *p);
// 获取协议中指定方法的方法描述
struct objc_method_description protocol_getMethodDescription ( Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod );
// 获取协议中指定条件的方法的方法描述数组
struct objc_method_description * protocol_copyMethodDescriptionList ( Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount );
// 获取协议的指定属性
objc_property_t protocol_getProperty ( Protocol *proto, const char *name, BOOL isRequiredProperty, BOOL isInstanceProperty );
// 获取协议中的属性列表
objc_property_t * protocol_copyPropertyList ( Protocol *proto, unsigned int *outCount );
// 返回协议中声明的属性列表
objc_property_t *protocol_copyPropertyList2(Protocol *proto, unsigned int *outCount, BOOL isRequiredProperty, BOOL isInstanceProperty)
// 获取协议遵循的协议
Protocol ** protocol_copyProtocolList ( Protocol *proto, unsigned int *outCount );
// 创建新的协议实例
Protocol * objc_allocateProtocol ( const char *name );
// 在运行时中注册新创建的协议
void objc_registerProtocol ( Protocol *proto );
// 向协议中添加方法,必须在协议未注册之前
void protocol_addMethodDescription ( Protocol *proto, SEL name, const char *types, BOOL isRequiredMethod, BOOL isInstanceMethod );
//添加一个已注册的协议到未注册的协议中
void protocol_addProtocol ( Protocol *proto, Protocol *addition );
// 为协议添加属性,必须在协议注册之前
void protocol_addProperty ( Protocol *proto, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount, BOOL isRequiredProperty, BOOL isInstanceProperty );
// 返回所有加载的Objective-C框架和动态库的名称
const char **objc_copyImageNames(unsigned int *outCount)
// 返回一个类所在的动态库名称
const char *class_getImageName(Class cls);
// 返回库中所有类的名称
const char **objc_copyClassNamesForImage(const char *image,unsigned int *outCount);
// 返回指定sel的方法的名称
const char *sel_getName(SEL sel);
// 使用OC运行时系统注册一个方法,将方法名映射到选择器SEL并返回SEL值
SEL sel_registerName(const char *str);
// 判断两个sel是否相同
BOOL sel_isEqual(SEL lhs, SEL rhs);
// 在每次迭代中检测到突变时,编译器插入此函数。 它在变异发生时被调用,并且如果设置了enumerationMutationHandler,则会执行。 如果未设置处理程序,则会发生致命错误。
void objc_enumerationMutation(id obj)
// 设置当前突变的处理程序
OBJC_EXPORT void objc_setEnumerationMutationHandler(void (*handler)(id));
// 设置objc_msgForward调用的函数。
void objc_setForwardHandler(void *fwd, void *fwd_stret)
// 创建一个当调用此方法时调用指定块的函数指针
IMP imp_implementationWithBlock(id block);
// 返回与使用imp_implementationWithBlock创建的IMP关联的块
id imp_getBlock(IMP anImp);
// 移除与使用imp_implementationWithBlock创建的IMP相关联的块的关联
BOOL imp_removeBlock(IMP anImp)
// 加载弱指针引用的对象并返回它
id objc_loadWeak(id *location);
// 存储_weak变量的新值
id objc_storeWeak(id *location, id obj);
// 设置对象对应key和和关联策略的关联值
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
// 获取对象给定key的关联值
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key);
// 移除对象的所有关联
void objc_removeAssociatedObjects(id object);
网友评论