Class extensions vs categories 类扩展与种类的异同

不论是你自己创建的类,还是系统自带的类,都可以用种类(category)在上面添加新方法。在实际的工作中,最常见的用法就是在系统自带的类上,让这些类用起来更顺手,比如 UILabel, NSArray 和 SKProduct 等。

而类扩展(extension)是种类(category)里一个特殊的部分,它就看起来像是和类同名的种类(category),因为它们自己没有名称;也没有种类(category)用途那么广泛,因为它们不能作用在系统自带的类上面。

尽管有诸多限制,但是因为在类扩展里可以添加属性、实例变量和方法,它们的功能还是非常强大。这和种类不一样,类扩展是和它所对应的类的源代码,是在同一时间编译运行的,工作方式更接近于 C#。

前面我们提到过用类扩展创建属性,这样就不用在头文件里面把属性暴露出来了,这是扩展非常常见的使用方式。有意思的是,在类扩展里有一个 redefine 属性,它的用法类似上面提到的逻辑。举个例子,我们可以把带 redefine 的属性定义在头文件里,然后在实现文件里面改变它。这个技术非常好用,但是讲实话,只有当你的团队里面有高级 Objective-C 开发者的时候,你才可能会碰到这种用法。但是这里还是要提一提,这样当你看到这个用法的时候,就可以装逼啦。

最常见的类扩展用法,还是和 readonly 属性一起用。创建只读属性的时候,编译器不会创建 setter 访问器,你只能读取这个属性,但是不能修改它。当你的 API 暴露在外部的时候,你会发现 readonly 会让代码更安全。但是如果你希望这个属性在类的内部是可以读写的,但是在外是只读的,就需要用到类扩展。我们可以在头文件里将属性声明为 readonly,但是在实现文件里面,把它重新声明为 readwrite,注意了,readwrite 实际上属性默认的修饰符,所以重新定义它的时候,是可以不写出来的。我们用代码来举例,首先在 Person.h 里,把属性声明为 readonly:

@property (readonly) NSString *name;

然后我们在 Person.m 文件里面这样写:

@interface Person ()
@property NSString *name;
@end

这样就好了,但是我觉得,下面的这种写法可以让代码可读性更强,也就是把 readwrite 修饰符添上去。所以啦,如果是我来写的话,我会这样写:

@interface Person ()
@property (readwrite) NSString *name;
@end

results matching ""

    No results matching ""