iOS基础---Category vs Extension

系列文章目录

iOS基础—多线程:GCD、NSThread、NSOperation
iOS基础—Category vs Extension


一、Category

1.Category是什么

Category(类别)是Objective-C 2.0之后添加的语言特性,允许开发者在不修改原有类的情况下,为其添加新的方法。Category 特别适用于扩展系统类和第三方类的功能。

我们在使用Xcode 创建文件时,可以将 File Type 指定为 Category,Class指定为我们要进行扩展的类:

在这里插入图片描述

然后就会自动生成 Person+Student.h 和 Person+Student.m 文件:

在这里插入图片描述

2. 使用场景

使用 Category 的好处是:

  1. 分离代码逻辑
    Category 可以将一个类的实现分成多个独立的部分,每个部分专注于不同的功能或逻辑。这使得代码更易于管理和维护。
  2. 扩展现有类
    Category 允许你为现有的类添加新功能,而无需子类化或修改原始类的代码。这对于扩展系统类(如 NSString, NSArray 等)尤其有用。
  3. 组织代码
    通过使用 Category,可以将相关的方法组织在一起,使代码更加模块化和易读。例如,可以为一个复杂的视图控制器创建多个 Category,每个 Category 处理视图控制器的不同方面。
  4. 简化代码重用
    Category 允许你在多个类中重用相同的代码,而无需复制粘贴。这对于通用的工具方法或功能特别有用。
  5. 动态加载功能
    Category 可以在运行时动态加载功能,这使得它们非常适合插件系统或模块化应用。

如果我们创建一个 MacOs 的 Command Line Tool 程序用 Category 对类进行扩展,会报错:

/Applications/code_test/category_test/main.m:17:14 No visible @interface for ‘Person’ declares the selector ‘PrintNameTwice’

这是因为 Command Line Tool 程序中函数的调用是编译时确定的,而 Category 是 Runtime 时加载的,所以我们创建一个 App 程序进行实验:

在这里插入图片描述

在这里插入图片描述

3.注意事项

分类只能增加方法,不能增加成员变量。

在这里插入图片描述

分类中的方法如果与原类的方法名相同,可能会覆盖原类的方法。

在这里插入图片描述

可以添加属性声明,但不能直接实现属性的存取方法(getter 和 setter)。关联对象(Associated Objects)是一种机制,允许为现有对象动态添加属性。它们使用 objc_setAssociatedObjectobjc_getAssociatedObject 函数来设置和获取值

在Objective-C中,属性(Property)通常由实例变量(Instance Variables)和访问方法(Getter和Setter)组成。当你在类的声明中添加一个属性时,编译器会自动生成相应的实例变量和访问方法。然而,在Category中,编译器无法为其添加实例变量,因为Category并不改变类的内存布局。

在这里插入图片描述
在这里插入图片描述

objc_setAssociatedObjectobjc_getAssociatedObject 的函数原型:

void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
//object: 需要关联值的对象。
//key: 用于唯一标识关联的键,通常使用静态地址或唯一的指针。
//value: 要关联的值,可以是任何对象。如果传入 nil,则会移除先前关联的值。
//policy: 关联策略,定义了关联对象的内存管理语义。
OBJC_ASSOCIATION_ASSIGN:指定一个弱引用关联对象,不保留新的值。
OBJC_ASSOCIATION_RETAIN_NONATOMIC:指定关联对象的强引用,且不使用原子操作。
OBJC_ASSOCIATION_COPY_NONATOMIC:指定关联对象的副本,且不使用原子操作。
OBJC_ASSOCIATION_RETAIN:指定关联对象的强引用,使用原子操作。
OBJC_ASSOCIATION_COPY:指定关联对象的副本,使用原子操作。


id objc_getAssociatedObject(id object, const void *key);
//object: 需要获取关联值的对象。
//key: 用于唯一标识关联的键,这个键必须与 objc_setAssociatedObject 时使用的键相同。

对于原理,美团技术团队已经做了深入的讲解:深入理解Objective-C:Category

二、Extension

在 iOS 开发中,类扩展(Class Extension)是一种用于在类的实现文件中声明私有方法和属性的机制。与 Category 不同,类扩展只能在类的实现文件中使用,并且必须在编译时确定。类扩展通常用于声明类的私有接口,隐藏实现细节,增强封装性。

类扩展的用途:

  • 声明私有属性:在类扩展中声明的属性只能在类的实现文件中访问。
  • 声明私有方法:在类扩展中声明的方法只能在类的实现文件中调用。
  • 提供更好的封装:通过将私有接口隐藏在实现文件中,类扩展提高了代码的封装性。

下面是一段在 MyClass.m 文件中对 MyClass 类进行扩展的代码:

// MyClass.m
#import "MyClass.h"

@interface MyClass ()
@property (nonatomic, strong) NSString *privateProperty; // 私有属性
- (void)privateMethod;// 私有方法
@end

@implementation MyClass
- (void)privateMethod {
    NSLog(@"Private Property: %@", self.privateProperty);
}
@end

三、对比

  1. 用途不同
  • Category
  1. 用于为现有类添加方法,而不需要修改原始类的代码。
  2. 可以在任何地方定义和使用。
  3. 主要用于将类的功能模块化、分离代码逻辑,或者为系统类添加新功能。
  • Extension
  1. 用于在类的实现文件中声明私有属性和方法。
  2. 只能在类的实现文件中使用。
  3. 主要用于隐藏实现细节,增强类的封装性。
  1. 添加内容的不同
  • Category:
  1. 只能添加方法,不能添加实例变量(成员变量)。
  2. 可以添加属性声明,但不能直接实现属性的存取方法(getter 和 setter)。
  • Extension:
  1. 可以添加方法和实例变量(成员变量)。
  2. 可以添加属性,并且可以在实现文件中实现属性的存取方法。
  1. 编译时 vs 运行时
  • Category:
  1. 在运行时加载,可以动态地为类添加方法。
  2. 方法的加载顺序可能影响方法的覆盖(如果多个 Category 添加了相同的方法)。
  • Extension:
  1. 在编译时确定,必须在类的实现文件中定义。
  2. 由于是在编译时确定的,类扩展中的方法和属性与类的其他部分一样被处理。
  1. 可见性
  • Category:
  1. 方法是公共的(public),可以被任何地方访问。
  2. 适用于对外扩展类的功能。
  • Extension:
  1. 方法和属性是私有的(private),只能在类的实现文件中访问。
  2. 适用于隐藏实现细节,增强封装性。
  • 16
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值