1. /// An opaque type that represents an Objective-C class.
  2. typedef struct objc_class *Class;
  3. /// Represents an instance of a class.
  4. struct objc_object {
  5. Class _Nonnull isa OBJC_ISA_AVAILABILITY;
  6. };
  7. /// A pointer to an instance of a class.
  8. typedef struct objc_object *id;

由此可见可以看到Classid 前者是类,后者指向类的指针,id是指向objc_object的一个指针,而objc_object有个isa指向objc_class的一个指针
So,不管id,还是Class最后指向的都是objc_class这个结构体
objc_class结构体中的定义如下:

  1. struct objc_class {
  2. Class _Nonnull isa OBJC_ISA_AVAILABILITY;
  3. #if !__OBJC2__
  4. Class _Nullable super_class OBJC2_UNAVAILABLE;
  5. const char * _Nonnull name OBJC2_UNAVAILABLE;
  6. long version OBJC2_UNAVAILABLE;
  7. long info OBJC2_UNAVAILABLE;
  8. long instance_size OBJC2_UNAVAILABLE;
  9. struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
  10. struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
  11. struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
  12. struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
  13. #endif
  14. } OBJC2_UNAVAILABLE;
  15. /* Use `Class` instead of `struct objc_class *` */
  1. /*
  2. * 顾名思义存放property的结构体
  3. * 当我们使用perproty的时候,会生成这样一个结构体
  4. * 具体存储的数据为
  5. * 实际内容:"Name","T@\"NSString\",C,N,VName"
  6. * 原型:@property (copy,nonatomic)NSString *Name;
  7. * 这个具体是怎么实现的,我会在后面继续深入研究,本文主要来理解runtime的理解
  8. **/
  9. struct _prop_t {
  10. const char *name; //名字
  11. const char *attributes; //属性
  12. };
  13. /*
  14. *类中方法的结构体,cmd和imp的关系是一一对应的关系
  15. *创建对象生成isa指针,指向这个对象的结构体时
  16. *同时生成了一个表"Dispatch table"通过这个_cmd的编号找到对应方法
  17. *使用场景:
  18. *例如方法交换,方法判断。。。
  19. **/
  20. struct _objc_method {
  21. struct objc_selector * _cmd; //SEL 对应着OC中的@selector()
  22. const char *method_type; //方法的类型
  23. void *_imp; //方法的地址
  24. };
  25. /*
  26. * method_list_t 结构体:
  27. * 原型:
  28. * - (void)GiveThisGameName:(NSString *)name;
  29. * 实际存储的方式:
  30. * {(struct objc_selector *)"GiveThisGameName:", "v24@0:8@16", (void *)_I_Game_GiveThisGameName_}
  31. * 其主要目的是存储一个数组,基本的数据类型是 _objc_method
  32. * 扩展:当然这其中有你的属性,自动生成的setter、getter方法
  33. **/
  34. static struct _method_list_t {
  35. unsigned int entsize; // sizeof(struct _objc_method)
  36. unsigned int method_count;
  37. struct _objc_method method_list[6];
  38. }
  39. /*
  40. * 表示这个类中所遵守的协议对象
  41. * 使用场景:
  42. * 判断类是否遵守这个协议,从而动态添加、重写、交换某些方法,来达到某些目的
  43. *
  44. **/
  45. struct _protocol_t {
  46. void * isa; // NULL
  47. const char *protocol_name;
  48. const struct _protocol_list_t * protocol_list; // super protocols
  49. const struct method_list_t *instance_methods; // 实例方法
  50. const struct method_list_t *class_methods; //类方法
  51. const struct method_list_t *optionalInstanceMethods; //可选的实例方法
  52. const struct method_list_t *optionalClassMethods; //可选的类方法
  53. const struct _prop_list_t * properties; //属性列表
  54. const unsigned int size; // sizeof(struct _protocol_t)
  55. const unsigned int flags; // = 0
  56. const char ** extendedMethodTypes; //扩展的方法类型
  57. };
  58. /*
  59. * 类的变量的结构体
  60. * 原型:
  61. * NSString *Name;
  62. * 存储内容:
  63. * {(unsigned long int *)&OBJC_IVAR_$_Game$Name, "Name", "@\"NSString\"", 3, 8}
  64. * 根据存储内容可以大概了解这些属性的工作内容
  65. **/
  66. struct _ivar_t {
  67. unsigned long int *offset; // pointer to ivar offset location
  68. const char *name; //名字
  69. const char *type; //属于什么变量
  70. unsigned int alignment; //未知
  71. unsigned int size; //大小
  72. };
  73. /*
  74. * 这个就是类中的各种方法、属性、等等信息
  75. * 底层也是一个结构体
  76. * 名称、方法列表、协议列表、变量列表、layout、properties。。
  77. *
  78. **/
  79. struct _class_ro_t {
  80. unsigned int flags;
  81. unsigned int instanceStart;
  82. unsigned int instanceSize;
  83. unsigned int reserved;
  84. const unsigned char *ivarLayout; //布局
  85. const char *name; //名字
  86. const struct _method_list_t *baseMethods;//方法列表
  87. const struct _objc_protocol_list *baseProtocols; //协议列表
  88. const struct _ivar_list_t *ivars; //变量列表
  89. const unsigned char *weakIvarLayout; //弱引用布局
  90. const struct _prop_list_t *properties; //属性列表
  91. };
  92. /*
  93. * 类本身
  94. * oc在创建类的时候都会创建一个 _class_t的结构体
  95. * 我的理解是在runtime中的object-class结构体在底层就会变成_class_t结构体
  96. **/
  97. struct _class_t {
  98. struct _class_t *isa; //元类的指针
  99. struct _class_t *superclass; //父类的指针
  100. void *cache; //缓存
  101. void *vtable; //表信息、未知
  102. struct _class_ro_t *ro; //这个就是类中的各种方法、属性、等等信息
  103. };
  104. /*
  105. * 类扩展的结构体
  106. * 在OC中写的分类
  107. **/
  108. struct _category_t {
  109. const char *name; //名称
  110. struct _class_t *cls; //这个是哪个类的扩展
  111. const struct _method_list_t *instance_methods; //实例方法列表
  112. const struct _method_list_t *class_methods; //类方法列表
  113. const struct _protocol_list_t *protocols; //协议列表
  114. const struct _prop_list_t *properties; //属性列表
  115. };

应用场景:

  • 关联对象(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

  1. <a name="HZDoX"></a>
  2. #### 方法魔法(Method Swizzling)方法添加和替换和KVO实现
  3. ```objectivec
  4. cls 被添加方法的类
  5. name 添加的方法的名称的SEL
  6. imp 方法的实现。该函数必须至少要有两个参数,self,_cmd
  7. types 类型编码
  8. //class_addMethod(Class _Nullable __unsafe_unretained cls, SEL _Nonnull name, IMP _Nonnull imp, const char * _Nullable types)
  9. class_addMethod([self class], sel, (IMP)fooMethod, "v@:");

方法替换
  1. @implementation ViewController
  2. + (void)load {
  3. static dispatch_once_t onceToken;
  4. dispatch_once(&onceToken, ^{
  5. Class class = [self class];
  6. SEL originalSelector = @selector(viewDidLoad);
  7. SEL swizzledSelector = @selector(jkviewDidLoad);
  8. Method originalMethod = class_getInstanceMethod(class,originalSelector);
  9. Method swizzledMethod = class_getInstanceMethod(class,swizzledSelector);
  10. //judge the method named swizzledMethod is already existed.
  11. BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
  12. // if swizzledMethod is already existed.
  13. if (didAddMethod) {
  14. class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
  15. }
  16. else {
  17. method_exchangeImplementations(originalMethod, swizzledMethod);
  18. }
  19. });
  20. }
  21. - (void)jkviewDidLoad {
  22. NSLog(@"替换的方法");
  23. [self jkviewDidLoad];
  24. }
  25. - (void)viewDidLoad {
  26. NSLog(@"自带的方法");
  27. [super viewDidLoad];
  28. }
  29. @end