当前位置:首页 > 技术知识 > 正文内容

Objective-C :Category(category什么意思)

maynowei11个月前 (08-02)技术知识186

Category 引入

在日常的开发中,可能会碰到这样的需求:给某个类增加方法。比如说,需要给NSString类增加一个打印的方法。当然,我们可以新建一个类比如TestString,并继承NSString类,在新的类TestString中实现 displayString方法。但是,这种方法有一个明显的缺陷是:只有 TestString类有该方法,NSString类的其他子类,比如 NSMutableString 不能使用该方法。能否给 NSString 类增加一个方法,让NSString以及NSString的所有子类都可以使用呢?答案可以的,Category可以完美的解决这个问题。

Category 的使用

Objective-C 中使用Category的语法是使用 @interface关键字,和定义一个标准的类非常类似,不过不是使用冒号(:,:是继承一个类时使用),而是使用 ,如下:

@interface NSString (PlayString)

- (void)playString:(NSString *)content;

@end

其中:括号内的 PlayStirng 是Category的名称。

可以为任何一个类增加 Category,即使看不到这个类的源代码。当为一个类增加Cateogry后,这个类以及这个类的所有子类都可以使用Category中的方法。在运行时,Category 中的方法和类中原来的代码是没有区别的。比如说,上例中,NSString 类增加Cateogry,Category中定义了 playString方法,该方法的实现如下:

- (void)playString:(NSString *)content
{
    NSLog(@"the content is %@",content);
}

这样,NSString类的实例对象,以及NSString类的所有子类的实例对象,都可以使用 playString方法。如下:

NSString *myString = @"this is original NSString";
[myString playString:myString];
    
NSMutableString *mutString = [[NSMutableString alloc] init];
[mutString appendString:@"this is a subclass of NSString"];
[mutString playString:mutString];

除了给一个类增加方法外,Category 还有以下两种使用场景:

1:将一个大的、复杂的类文件拆分成几个小的类文件。

2:多个人开发同一个类文件时,可以使用Category,分别开发自己的功能。

使用Category的注意事项

1:Category中方法的命名。

(1):尽量不要和原始类中的方法重名,尽管这样是合法的,但是和原始类中的方法重名绝对不是一个好的编程习惯。因为这样造成的后果是,无论是原始类,还是原始类的子类,都无法使用原始类中的那个方法。通常来说,想要覆盖父类中某个方法的情况,更适合用继承来实现,而不是Category。

(2):当一个原始类有多个 Category 时,各个Category 中的方法名要保持相异。尽管多个Category中方法名重复不会提醒错误,但是会发生一些莫名其妙的错误。多个Category中的方法名重复时,每个Category都会向原始类中增加一个函数,这样在运行时,所调用的方法和我们所期望的可能会不一致。这种情况下,具体调用哪个Category中的方法和编译器是相关的。

2:Category中不能增加实例变量。虽然在Category中可以增加属性,但是在 .m文件中,编译器不会自动合成实例变量,以及访问实例变量的 getter/setter 方法。想要为某个原始类增加实例变量,这种情况可以用继承来实现。

Category 原理初探

实际上,Objective-C 中的类经过编译后,在内存中都有一个方法列表,方法列表指向的是该方法的代码块地址。当向某个方法发送消息时,就从方法列表中寻找方法。举例来说有一个类 Person,该类经过编译后生成的方法列表是: setName、getName、getSex ……。现在该类增加一个Category,Category中也实现了方法getName,则再次经过编译后,生成的方法列表是: setName、getName(Category)、getName(原始类)、getSex ……,当给getName方法发送消息时,从类的方法列表中寻找,找到第一个getName方法时,就不在继续往下寻找,这样使用的永远是 Category中实现的 getName 方法。这也是为何要注意Category中方法命名的原因。

相关文章

C++ 原子操作与锁的深度解析:为什么原子操作并非万金油?

大噶好,我是henry,今天来和大家浅浅聊一下为啥C++原子操作并非万能钥匙,原因有三,且听我娓娓道来:一、原子操作的线程安全性C++11 的 std::atomic 确实为单个变量的线程安全操作提供...

LabVIEW实现Oracle数据库的访问(labview数据库查询界面)

1. 安装 Oracle 客户端下载:从 Oracle 官方网站下载适用于 Windows 操作系统的 Oracle 驱动程序。确保下载的版本与 LabVIEW 环境和操作系统兼容。1)以 Windo...

一个快要被忘记的数据库开发岗位,但应该被尊重

数据库测试,似乎是被人遗忘的数据库职业,但依然是不错的选择。底下是我在某站找的招聘启事,就连蚂蚁金服都在积极寻找数据库测试人:要说我经历的项目,大大小小也有几十个,从 C/S, B/S, 再到 B/C...

python-oracledb——利用python连接Oracle数据库的好用方法

这篇文章最早发布在CSDN了,最近想尝试使用一下头条,重新转移过来了。背景介绍之前使用的数据库一直是MySql,偶尔使用PostgreSQL,都是利用的数据库连接池使用;最近需要在Oracle数据库取...

6 张图带你彻底搞懂分布式事务 XA 模式

XA 协议是由 X/Open 组织提出的分布式事务处理规范,主要定义了事务管理器 TM 和局部资源管理器 RM 之间的接口。目前主流的数据库,比如 oracle、DB2 都是支持 XA 协议的。mys...

超详细的Oracle19c修改数据库用户名教程

概述由于开发很多视图指定了某个用户名,故需修改数据库用户名srmpro为srm。以下为操作过程..1、停止应用防止修改用户名密码后应用一直在发起错误连接,可事先查询哪个IP在连接数据库,然后断开对应连...