Objective-C - category学习笔记
面向对象的编程语言通常通过继承来重用代码,对原有的类进行功能扩展。而OC除提供继承的方式扩展已有类以外,还提供了category类扩展机制。category扩展类不需要创建新的子类,也不需要访问类代码。
category语法
此处以BNRPerson
类为例子来说明如何使用category机制对其进行扩展。下面为BNRPerson
的声明,实现就省略了。
@interface BNRPerson : NSObject
// 使用property使得编译器自动生成访问器
// 指明属性和类型
@property (nonatomic, readwrite) float heightInMeters;
@property (nonatomic) int weightInKilos;
// 身体质量指数
- (float)bodyMassIndex;
@end
刘慈欣在《天使时代》里面通过基因编程的方式成功为人类增加了翅膀,使得人类具备了飞行能力。现在通过category机制为BNRPerson
增加飞行能力。首先创建新文件BNRPerson+Wings.h
,并添加如下代码。
#import "BNRPerson.h"
@interface BNRPerson (Wings)
- (void)flyInTheSky;
@end
语法非常类似于类的定义,但是需要注意的是没有继承任何父类,而且类名不变,只是在后面增加了(Wings)
。然后增加了一个新的方法flyInTheSky
。
通过category扩展类以后需要对其实现,创建文件BNRPerson+Wings.m
,并增加如下的代码。
#import "BNRPerson+Wings.h"
@implementation BNRPerson (Wings)
- (void)flyInTheSky
{
NSLog(@"Human beens with wings also belong to human");
}
@end
注意:
导入的头文件为BNRPerson+Wings.h
,并为方法flyInTheSky
添加了实现。
category调用
调用方式也非常简单,就相当于BNRPerson
多了一个成员方法,和BNRPerson
的其他方法调用方式没有什么区别。下面的测试程序测试了调用category的功能。
#import <Foundation/Foundation.h>
#import "BNRPerson+Wings.h"
int main(int argc, const char* argv[])
{
BNRPerson *mikey = [[BNRPerson alloc] init];
[mikey setHeightInMeters:1.8];
mikey.heightInMeters=1.8;
[mikey setWeightInKilos:96];
float height = [mikey heightInMeters];
int weight = [mikey weightInKilos];
NSLog(@"mikey is %.2f meters tall and weights %d kilograms", height, weight);
// 点记法访问函数也完全没有问题
float bmi = mikey.bodyMassIndex;
// float bmi = [mikey bodyMassIndex];
NSLog(@"mikey has a BMI of %f", bmi);
[mikey flyInTheSky];
return 0;
}
注意:
头文件为BNRPerson+Wings.h
而非BNRPerson.h
,其实后者也可以,至少我测试时没出问题,只是编译时给了找不到方法的警告,但是前者肯定不会出错。
category应用场景
本节完全参考池建强老师的博客,地址如下:http://www.cnblogs.com/chijianqiang/archive/2012/06/22/objc-category-protocol.html
- 当你在定义类的时候,在某些情况下(例如需求变更),你可能想要为其中的某个或几个类中添加方法。
- 一个类中包含了许多不同的方法需要实现,而这些方法需要不同团队的成员实现
- 当你在使用基础类库中的类时,你可能希望这些类实现一些你需要的方法。
遇到以上这些需求,category可以帮助你解决问题。当然,使用category也有些问题需要注意,具体如下:
- category可以访问原始类的实例变量,但不能添加变量,如果想添加变量,可以考虑通过继承创建子类。
- category 可以重载原始类的方法,但不推荐这么做,这么做的后果是你再也不能访问原来的方法。如果确实要重载,正确的选择是创建子类。
- 和普通接口有所区别的是,在category的实现文件中可以不必实现所有声明的方法,只要你不去调用它。