深入理解Objective-C:Category(上)
来源:互联网 发布:淘宝小号信誉查询 编辑:程序博客网 时间:2024/04/30 09:10
摘要
无论一个类设计的多么完美,在未来的需求演进中,都有可能会碰到一些无法预测的情况。那怎么扩展已有的类呢?一般而言,继承和组合是不错的选择。但是在Objective-C 2.0中,又提供了category这个语言特性,可以动态地为已有类添加新行为。如今category已经遍布于Objective-C代码的各个角落,从Apple官方的framework到各个开源框架,从功能繁复的大型APP到简单的应用,catagory无处不在。本文对category做了比较全面的整理,希望对读者有所裨益。
简介
本文作者来自美团酒店旅游事业群iOS研发组。我们致力于创造价值、提升效率、追求卓越。欢迎大家加入我们(简历请发送到邮箱majia03@meituan.com)。
本文系学习Objective-C的runtime源码时整理所成,主要剖析了category在runtime层的实现原理以及和category相关的方方面面,内容包括:
初入宝地-category简介
连类比事-category和extension
挑灯细览-category真面目
追本溯源-category如何加载
旁枝末叶-category和+load方法
触类旁通-category和方法覆盖
更上一层-category和关联对象
1、初入宝地-category简介
category是Objective-C 2.0之后添加的语言特性,category的主要作用是为已经存在的类添加方法。除此之外,apple还推荐了category的另外两个使用场景1
可以把类的实现分开在几个不同的文件里面。这样做有几个显而易见的好处,a)可以减少单个文件的体积 b)可以把不同的功能组织到不同的category里 c)可以由多个开发者共同完成一个类 d)可以按需加载想要的category 等等。
声明私有方法
不过除了apple推荐的使用场景,广大开发者脑洞大开,还衍生出了category的其他几个使用场景:
模拟多继承
把framework的私有方法公开
Objective-C的这个语言特性对于纯动态语言来说可能不算什么,比如javascript,你可以随时为一个“类”或者对象添加任意方法和实例变量。但是对于不是那么“动态”的语言而言,这确实是一个了不起的特性。
2、连类比事-category和extension
extension看起来很像一个匿名的category,但是extension和有名字的category几乎完全是两个东西。 extension在编译期决议,它就是类的一部分,在编译期和头文件里的@interface以及实现文件里的@implement一起形成一个完整的类,它伴随类的产生而产生,亦随之一起消亡。extension一般用来隐藏类的私有信息,你必须有一个类的源码才能为一个类添加extension,所以你无法为系统的类比如NSString添加extension。(详见2)
但是category则完全不一样,它是在运行期决议的。
就category和extension的区别来看,我们可以推导出一个明显的事实,extension可以添加实例变量,而category是无法添加实例变量的(因为在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,这对编译型语言来说是灾难性的)。
3、挑灯细览-category真面目
我们知道,所有的OC类和对象,在runtime层都是用struct表示的,category也不例外,在runtime层,category用结构体category_t(在objc-runtime-new.h中可以找到此定义),它包含了
1)、类的名字(name)
2)、类(cls)
3)、category中所有给类添加的实例方法的列表(instanceMethods)
4)、category中所有添加的类方法的列表(classMethods)
5)、category实现的所有协议的列表(protocols)
6)、category中添加的所有属性(instanceProperties)
typedef struct category_t {
const char *name;
classref_t cls;
struct method_list_t *instanceMethods;
struct method_list_t *classMethods;
struct protocol_list_t *protocols;
struct property_list_t *instanceProperties;
} category_t;
从category的定义也可以看出category的可为(可以添加实例方法,类方法,甚至可以实现协议,添加属性)和不可为(无法添加实例变量)。
ok,我们先去写一个category看一下category到底为何物:
MyClass.h:
#import <Foundation/Foundation.h>
@interface MyClass : NSObject
- (void)printName;
@end
@interface MyClass(MyAddition)
@property(nonatomic, copy) NSString *name;
- (void)printName;
@end
MyClass.m:
#import "MyClass.h"
@implementation MyClass
- (void)printName
{
NSLog(@"%@",@"MyClass");
}
@end
@implementation MyClass(MyAddition)
- (void)printName
{
NSLog(@"%@",@"MyAddition");
}
@end
我们使用clang的命令去看看category到底会变成什么:
clang -rewrite-objc MyClass.m
好吧,我们得到了一个3M大小,10w多行的.cpp文件(这绝对是Apple值得吐槽的一点),我们忽略掉所有和我们无关的东西,在文件的最后,我们找到了如下代码片段:
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_MyClass_$_MyAddition __attribute__ ((used, section("__DATA,__objc_const"))) = {
sizeof(_objc_method),
1,
{{(struct objc_selector *)"printName", "v16@0:8", (void *)_I_MyClass_MyAddition_printName}}
};
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_MyClass_$_MyAddition __attribute__ ((used, section ("__DATA,__objc_const")))
- 深入理解Objective-C:Category(上)
- 深入理解Objective-C:Category(上)
- 深入理解Objective-C:Category(上)
- 深入理解Objective-C:Category
- 深入理解Objective-C:Category
- 深入理解Objective-C:Category
- 深入理解Objective-C:Category
- 深入理解Objective-C:Category
- 深入理解Objective-C:Category
- 深入理解Objective-C:Category
- 深入理解Objective-C:Category
- 深入理解Objective-C:Category
- 深入理解Objective-C:Category(下)
- 深入理解Objective-C:Category(下)
- Objective-C:理解Category
- 深入理解Objective-C:Category (原文基础上有改动)
- 一定要看的。深入理解Objective-C:Category
- 深入理解 Objective-C Runtime
- 解决浏览器记住密码输入框的问题
- 第五章-算法入门
- 非静态成员的sizeof
- win2003右键没有(共享和安全)的问题
- 分享 Matlab实现视频图像前景分割
- 深入理解Objective-C:Category(上)
- UVa 165 - Stamps
- Selenium+autoit+java 上传文件
- Android自定义控件---“取消”视图
- 客户端时间存储的取舍
- Android 绘图笔记(一)Region
- linux 环境变量设置、指令学习、日常用到的linux知识
- C++中虚析构函数的作用
- php JSON数据格式化方法