Objective-C 2.0
中新增的语言特性
扩展已有的类 (仅限于为已有类增加方法) ;
分割类实现 ;
官方原文: Distribute the implementation of your own classes into separate source files—for example, you could group the methods of a large class into several categories and put each category in a different file.
几个显而易见的好处 :
a. 可以减少单个文件的体积 ;
b. 可以把不同的功能组织到不同的category里 ;
c. 可以由多个开发者共同完成一个类 ;
d. 可以按需加载想要的category ;
声明私有方法 ; (虽然是apple推荐, 但我并没有理解这么做有什么卵用) ;
/** 官方示例代码, MyClass.m file*/
#import "MyClass.h"@interface MyClass (PrivateMethods)
// private method declarations
@end@implementation MyClass
// private method definitions
@end
模拟多继承 ;
把framework的私有方法公开 ;
所有的Objective-C
的类和对象,在 runtime 层都是用 struct 表示的,category 也不例外, 在 objc-class.h
中, 找到如下定义 :
/* * Category Template*/
typedef struct objc_category *Category;struct objc_category {char *category_name;char *class_name;struct objc_method_list *instance_methods;struct objc_method_list *class_methods;struct objc_protocol_list *protocols;
};
从 Category
的定义中, 不难窥测, 其可为与不可也 ~ (可以增加 instance_methods, class_methods, protocols, 不可增加 instance, 故若在 Category 中新增 Property, 本质只会保留方法声明)
/** SQIClass.h 文件*/#import @interface SQIClass : NSObject- (void)sqiFunc;@end@interface SQIClass(SQIAddition)@property(nonatomic, copy) NSString *sqiProperty;- (void)sqiFunc;@end
/** SQIClass.m 文件*/#import "SQIClass.h"@implementation SQIClass- (void)sqiFunc
{NSLog(@"%@",@"I'm SQIClass func");
}@end@implementation SQIClass(SQIAddition)- (void)sqiFunc
{NSLog(@"%@",@"I'm SQIAddition func");
}@end
$ clang -rewrite-objc SQIClass.m
clang -rewrite-objc
的作用是把oc代码转写成c/c++代码,这里选用它来窥探OC Category
的底层实现.
以上命令会在当前目录生成大小为 3.8MB 的文件 (SQIClass.cpp), 代码共 65475 行 🤣🤮
生成文件及相关源码下载地址
// 起始于 65354 行
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;
};
与上文的 struct objc_category
基本一一对应, 多出来的 properties 暂时忽略.
// 起始于 65431 行
static struct /*_method_list_t*/ {unsigned int entsize; // sizeof(struct _objc_method)unsigned int method_count;struct _objc_method method_list[1];
} _OBJC_$_CATEGORY_INSTANCE_METHODS_SQIClass_$_SQIAddition __attribute__ ((used, section ("__DATA,__objc_const"))) = {sizeof(_objc_method),1,{{(struct objc_selector *)"sqiFunc", "v16@0:8", (void *)_I_SQIClass_SQIAddition_sqiFunc}}
};
实例方法列表为: _OBJC_$_CATEGORY_INSTANCE_METHODS_SQIClass_$_SQIAddition
, method_count 值为 1, 说明共有 1 个方法.
// 起始于 65441 行
static struct /*_prop_list_t*/ {unsigned int entsize; // sizeof(struct _prop_t)unsigned int count_of_properties;struct _prop_t prop_list[1];
} _OBJC_$_PROP_LIST_SQIClass_$_SQIAddition __attribute__ ((used, section ("__DATA,__objc_const"))) = {sizeof(_prop_t),1,{{"sqiProperty","T@\"NSString\",C,N"}}
};
属性列表为: _OBJC_$_PROP_LIST_SQIClass_$_SQIAddition
, count_of_properties 的值为 1, 说明共有 1 个属性.
static struct _category_t _OBJC_$_CATEGORY_SQIClass_$_SQIAddition __attribute__ ((used, section ("__DATA,__objc_const"))) =
{"SQIClass",0, // &OBJC_CLASS_$_SQIClass,(const struct _method_list_t *)&_OBJC_$_CATEGORY_INSTANCE_METHODS_SQIClass_$_SQIAddition,0,0,(const struct _prop_list_t *)&_OBJC_$_PROP_LIST_SQIClass_$_SQIAddition,
};
objc_catlist section
里保存了一个大小为1的_category_t的数组// start line: 65472
static struct _category_t *L_OBJC_LABEL_CATEGORY_$ [1] __attribute__((used, section ("__DATA, __objc_catlist,regular,no_dead_strip")))= {&_OBJC_$_CATEGORY_SQIClass_$_SQIAddition,
};