/// An opaque type that represents an Objective-C class.typedef struct objc_class *Class;/// Represents an instance of a class.struct objc_object {Class _Nonnull isa OBJC_ISA_AVAILABILITY;};/// A pointer to an instance of a class.typedef struct objc_object *id;
由此可见可以看到Class、id 前者是类,后者指向类的指针,id是指向objc_object的一个指针,而objc_object有个isa指向objc_class的一个指针
So,不管id,还是Class最后指向的都是objc_class这个结构体objc_class结构体中的定义如下:
struct objc_class {Class _Nonnull isa OBJC_ISA_AVAILABILITY;#if !__OBJC2__Class _Nullable super_class OBJC2_UNAVAILABLE;const char * _Nonnull name OBJC2_UNAVAILABLE;long version OBJC2_UNAVAILABLE;long info OBJC2_UNAVAILABLE;long instance_size OBJC2_UNAVAILABLE;struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;#endif} OBJC2_UNAVAILABLE;/* Use `Class` instead of `struct objc_class *` */
/** 顾名思义存放property的结构体* 当我们使用perproty的时候,会生成这样一个结构体* 具体存储的数据为* 实际内容:"Name","T@\"NSString\",C,N,VName"* 原型:@property (copy,nonatomic)NSString *Name;* 这个具体是怎么实现的,我会在后面继续深入研究,本文主要来理解runtime的理解**/struct _prop_t {const char *name; //名字const char *attributes; //属性};/**类中方法的结构体,cmd和imp的关系是一一对应的关系*创建对象生成isa指针,指向这个对象的结构体时*同时生成了一个表"Dispatch table"通过这个_cmd的编号找到对应方法*使用场景:*例如方法交换,方法判断。。。**/struct _objc_method {struct objc_selector * _cmd; //SEL 对应着OC中的@selector()const char *method_type; //方法的类型void *_imp; //方法的地址};/** method_list_t 结构体:* 原型:* - (void)GiveThisGameName:(NSString *)name;* 实际存储的方式:* {(struct objc_selector *)"GiveThisGameName:", "v24@0:8@16", (void *)_I_Game_GiveThisGameName_}* 其主要目的是存储一个数组,基本的数据类型是 _objc_method* 扩展:当然这其中有你的属性,自动生成的setter、getter方法**/static struct _method_list_t {unsigned int entsize; // sizeof(struct _objc_method)unsigned int method_count;struct _objc_method method_list[6];}/** 表示这个类中所遵守的协议对象* 使用场景:* 判断类是否遵守这个协议,从而动态添加、重写、交换某些方法,来达到某些目的***/struct _protocol_t {void * isa; // NULLconst char *protocol_name;const struct _protocol_list_t * protocol_list; // super protocolsconst struct method_list_t *instance_methods; // 实例方法const struct method_list_t *class_methods; //类方法const struct method_list_t *optionalInstanceMethods; //可选的实例方法const struct method_list_t *optionalClassMethods; //可选的类方法const struct _prop_list_t * properties; //属性列表const unsigned int size; // sizeof(struct _protocol_t)const unsigned int flags; // = 0const char ** extendedMethodTypes; //扩展的方法类型};/** 类的变量的结构体* 原型:* NSString *Name;* 存储内容:* {(unsigned long int *)&OBJC_IVAR_$_Game$Name, "Name", "@\"NSString\"", 3, 8}* 根据存储内容可以大概了解这些属性的工作内容**/struct _ivar_t {unsigned long int *offset; // pointer to ivar offset locationconst char *name; //名字const char *type; //属于什么变量unsigned int alignment; //未知unsigned int size; //大小};/** 这个就是类中的各种方法、属性、等等信息* 底层也是一个结构体* 名称、方法列表、协议列表、变量列表、layout、properties。。***/struct _class_ro_t {unsigned int flags;unsigned int instanceStart;unsigned int instanceSize;unsigned int reserved;const unsigned char *ivarLayout; //布局const char *name; //名字const struct _method_list_t *baseMethods;//方法列表const struct _objc_protocol_list *baseProtocols; //协议列表const struct _ivar_list_t *ivars; //变量列表const unsigned char *weakIvarLayout; //弱引用布局const struct _prop_list_t *properties; //属性列表};/** 类本身* oc在创建类的时候都会创建一个 _class_t的结构体* 我的理解是在runtime中的object-class结构体在底层就会变成_class_t结构体**/struct _class_t {struct _class_t *isa; //元类的指针struct _class_t *superclass; //父类的指针void *cache; //缓存void *vtable; //表信息、未知struct _class_ro_t *ro; //这个就是类中的各种方法、属性、等等信息};/** 类扩展的结构体* 在OC中写的分类**/struct _category_t {const char *name; //名称struct _class_t *cls; //这个是哪个类的扩展const struct _method_list_t *instance_methods; //实例方法列表const struct _method_list_t *class_methods; //类方法列表const struct _protocol_list_t *protocols; //协议列表const struct _prop_list_t *properties; //属性列表};
应用场景:
- 关联对象(Objective-C Associated Objects)给分类增加属性
- 方法魔法(Method Swizzling)方法添加和替换和KVO实现
- 消息转发(热更新)解决Bug(JSPatch)
- 实现NSCoding的自动归档和自动解档
- 实现字典和模型的自动转换(MJExtension)
关联对象(Objective-C Associated Objects)给分类增加属性
```objectivec //关联对象 void objc_setAssociatedObject(id object, const void key, id value, objc_AssociationPolicy policy) //获取关联的对象 id objc_getAssociatedObject(id object, const void key) //移除关联的对象 void objc_removeAssociatedObjects(id object)
//参数说明
id object:被关联的对象
const void *key:关联的key,要求唯一,有两种(sel或者常量)
id value:关联的对象
objc_AssociationPolicy policy:内存管理的策略
//示例
import “ViewController.h”
import “objc/runtime.h”
@interface UIView (DefaultColor)
@property (nonatomic, strong) UIColor *defaultColor;
@end
@implementation UIView (DefaultColor)
@dynamic defaultColor;
static char kDefaultColorKey;
(void)setDefaultColor:(UIColor *)defaultColor { objc_setAssociatedObject(self, &kDefaultColorKey, defaultColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }
(id)defaultColor { return objc_getAssociatedObject(self, &kDefaultColorKey); }
@end
@interface ViewController ()
@end
@implementation ViewController
(void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib.
UIView *test = [UIView new]; test.defaultColor = [UIColor blackColor]; NSLog(@”%@”, test.defaultColor); }
@end
<a name="HZDoX"></a>#### 方法魔法(Method Swizzling)方法添加和替换和KVO实现```objectiveccls 被添加方法的类name 添加的方法的名称的SELimp 方法的实现。该函数必须至少要有两个参数,self,_cmdtypes 类型编码//class_addMethod(Class _Nullable __unsafe_unretained cls, SEL _Nonnull name, IMP _Nonnull imp, const char * _Nullable types)class_addMethod([self class], sel, (IMP)fooMethod, "v@:");
方法替换
@implementation ViewController+ (void)load {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{Class class = [self class];SEL originalSelector = @selector(viewDidLoad);SEL swizzledSelector = @selector(jkviewDidLoad);Method originalMethod = class_getInstanceMethod(class,originalSelector);Method swizzledMethod = class_getInstanceMethod(class,swizzledSelector);//judge the method named swizzledMethod is already existed.BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));// if swizzledMethod is already existed.if (didAddMethod) {class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));}else {method_exchangeImplementations(originalMethod, swizzledMethod);}});}- (void)jkviewDidLoad {NSLog(@"替换的方法");[self jkviewDidLoad];}- (void)viewDidLoad {NSLog(@"自带的方法");[super viewDidLoad];}@end
