OC基础之扩展,分类与关联对象

143 阅读3分钟

写oc的朋友们,肯定对分类扩展很熟悉了。ategory(分类)和extension(扩展)都是用于扩展已有类的功能的机制。但也有

Category(分类)

  1. 定义和语法
  • Category 的语法形式为:@interface 原类名 (分类名) <协议列表>,然后在实现文件中使用@implementation 原类名 (分类名)来实现分类中的方法。
  • 例如:@interface NSString (MyCategory)... @end@implementation NSString (MyCategory)... @end

作用

  • 可以为已有类添加新的方法,而无需修改原类的代码。比如为 NSString 添加一些处理特定字符串格式的方法。
  • 可以将一个庞大的类的功能拆分成多个分类,使代码更易于管理和维护。

缺点

  • 命名冲突: 如果多个分类中为同一个类添加了同名的方法,会导致不确定性,具体哪个分类中的方法被调用取决于链接的顺序,可能会引发难以调试的问题。

  • 无法添加实例变量: 虽然可以通过关联对象的方式来模拟添加实例变量,但这种方式相对复杂且不是真正的实例变量,在性能和内存管理上可能不如原生的实例变量。

  • 可能覆盖原有方法: 如果不小心在分类中覆盖了原类中的方法,可能会导致不可预期的结果,尤其是在处理系统类或第三方库的类时。

Extension(扩展)

  1. 定义和语法
  • 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)函数来移除一个对象的所有关联对象。