写oc的朋友们,肯定对分类扩展很熟悉了。ategory(分类)和extension(扩展)都是用于扩展已有类的功能的机制。但也有
Category(分类)
- 定义和语法
- Category 的语法形式为:
@interface 原类名 (分类名) <协议列表>,然后在实现文件中使用@implementation 原类名 (分类名)来实现分类中的方法。 - 例如:
@interface NSString (MyCategory)... @end和@implementation NSString (MyCategory)... @end。
作用
- 可以为已有类添加新的方法,而无需修改原类的代码。比如为
NSString添加一些处理特定字符串格式的方法。 - 可以将一个庞大的类的功能拆分成多个分类,使代码更易于管理和维护。
缺点
-
命名冲突: 如果多个分类中为同一个类添加了同名的方法,会导致不确定性,具体哪个分类中的方法被调用取决于链接的顺序,可能会引发难以调试的问题。
-
无法添加实例变量: 虽然可以通过关联对象的方式来模拟添加实例变量,但这种方式相对复杂且不是真正的实例变量,在性能和内存管理上可能不如原生的实例变量。
-
可能覆盖原有方法: 如果不小心在分类中覆盖了原类中的方法,可能会导致不可预期的结果,尤其是在处理系统类或第三方库的类时。
Extension(扩展)
- 定义和语法
- Extension 的语法形式为:
@interface 原类名 () <协议列表>,然后在实现文件中紧挨着原类的@implementation部分来实现扩展中的方法和属性。 - 例如:
@interface NSString ()... @end和@implementation NSString... // 扩展的实现部分在这里... @end。
作用
- 可以为已有类添加新的方法和私有属性。
- 通常用于将类的一些私有实现细节封装在扩展中,以保持类的接口简洁。
优点
- 与分类不同,扩展可以添加实例变量,但这些实例变量只能在原类的实现文件中访问,是真正的私有变量。
- 扩展在编译时就会被合并到原类中,所以在运行时和原类没有区别。
缺点
- 过度使用扩展,会导致原文件臃肿
关联对象(Associated Objects)
允许你为一个已经存在的类添加类似于实例变量的存储。这是一种在运行时动态地为对象关联额外数据的机制。
作用
扩展类的功能
- 当你不能直接修改一个类的源代码时,可以使用关联对象为该类的实例添加额外的状态。例如,为系统提供的类或者第三方库中的类添加一些自定义的数据存储。
实现类似私有实例变量的效果
-
在分类中,不能直接添加实例变量,但可以通过关联对象来模拟私有实例变量的效果。
用法
添加关联对象
-
使用
(void) objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)函数来为一个对象关联一个值。- 参数说明:
`object`:要关联值的对象。
`key`:用于标识关联对象的键,通常是一个静态变量或全局变量。
`value`:要关联的对象。
`policy`:关联策略,决定了关联对象的内存管理方式。有下面几种:
1. `OBJC_ASSOCIATION_ASSIGN`:弱引用,不持有关联对象。
2. `OBJC_ASSOCIATION_RETAIN_NONATOMIC`:非原子性持有关联对象,相当于 `retain`。
3. `OBJC_ASSOCIATION_COPY_NONATOMIC`:非原子性复制关联对象。
4. `OBJC_ASSOCIATION_RETAIN`:原子性持有关联对象,相当于在属性声明中使用 `@property (nonatomic, strong)`。
5. `OBJC_ASSOCIATION_COPY`:原子性复制关联对象,相当于在属性声明中使用 `@property (atomic, copy)`。
-
使用
(id) objc_getAssociatedObject(id object, const void *key)函数来获取与一个对象关联的值。 -
使用
(void) objc_removeAssociatedObjects(id object)函数来移除一个对象的所有关联对象。