一 category的概念
分类的目的是在不改变原先类的基础上以达到扩展类方法的目的。category是OC特有的语法,在C中并没有分类的概念。
二 category的作用
1)不修改原类,而为原类增加方法
2)修改原类中某些方法的bug,即让分类方法覆盖原类旧方法
3)将类的内容存储在多个文件中
4)便于团队开发合作
5) 将常用的相关的方法分组
三 cagegory的用法格式
头文件格式:
@interface 类名 (分类名称)
@end
实现文件格式:
@implementation 类名 (分类名称)
@end
使用过程中要加入原类的头文件,否则不会识别类名
四 category的测试用例
例1:分类和原类完全分开
//main.m
#import <Foundation/Foundation.h>
#import "animal+animal_ext.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
animal *a1 = [animal new];
[a1 run]; //原类方法
[a1 legs:4]; //分类方法
[a1 printleg]; //原类方法
}
return 0;
}
//原类.h和.m文件
// animal.h
#import <Foundation/Foundation.h>
#import "animal.h"
@interface animal : NSObject
@property (nonatomic,assign) int leg;
-(void) run;
-(void) printleg;
@end
/***************************************/
// animal.m
#import "animal.h"
@implementation animal
-(void) run
{
NSLog(@"the animal is running");
}
-(void) printleg
{
NSLog(@"the animal has %d legs",_leg);
}
@end
//分类.h和.m文件
// class1+animal_ext.h
#import "animal.h"
@interface animal (animal_ext)
-(void) legs:(int)d;
@end
/***************************************/
// class1+animal_ext.m
#import "animal+animal_ext.h"
@implementation animal (animal_ext)
-(void) legs:(int)d
{
self.leg = d; //分类访问原类变量
}
@end
程序运行结果:
可见分类可以访问原类的变量,访问方式是用self访问。
下面增加animal有子类(dog类),让它重写原类printleg方法,以及查看是否能使用分类方法
//dog类.h和.m文件
// dog.h
#import "animal.h"
@interface dog : animal
@end
/***************************************/
// dog.m
#import "dog.h"
@implementation dog
-(void) printleg
{
NSLog(@"dog has %d legs",self.leg);
}
@end
运行结果:
由上图可以看到,dog类重写了原类的printleg方法以适应dog自己的特点,而且它也继承了原类的分类方法。
如果有原类有多个分类,而且有方法名重复,那么子类在调用会调用最后一次编译的那个分类中的方法。如图:
例2:category的非正式协议
// main.m
#import <Foundation/Foundation.h>
#import "person.h"
#import "NSObject+category.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
person *per = [person new];
[per print];
}
return 0;
}
//给NSObject增加的分类
// NSObject+category.h
#import <Foundation/Foundation.h>
@interface NSObject (NSObject_category)
-(void) print;
@end
/***************************************/
// NSObject+category.m
#import "NSObject+category.h"
@implementation NSObject (NSObject_category)
-(void) print
{
NSLog(@"我是非正式协议");
}
@end
//继承NSObject
// person.h
#import <Foundation/Foundation.h>
@interface person : NSObject
@end
/***************************************/
// person.m
#import "person.h"
@implementation person
@end
运行结果:
可见为NSObject增加分类的话,那么继承它的类都可以使用分类,所以 这个部分要好好考虑要不要增加分类,如果增加也要增加一个通用的分类。否则会造成意想不到的后果。
例3:category的Extention
它是cagegory的一个特例,没有分类名字,它可以分原类添加变量
下面是例子的代码,代码的其它部分和例1一样,就不再写了,这里只写extention代码和man.m中,以及原类的实现的代码
//修改过的main.m,主要是分了测试extention
// main.m
#import <Foundation/Foundation.h>
#import "animal+animal_ext.h"
#import "animal_extention.h"
#import "dog.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
animal *a1 = [animal new];
[a1 run]; //原类方法
[a1 legs:4]; //分类方法
[a1 printleg]; //原类方法
dog *d1 = [dog new];
[d1 legs:4];
[d1 printleg];
[d1 eat:6];
}
return 0;
}
//新增加的extention头文件
// animal_extention.h
#import "animal.h"
@interface animal ()
{
int maxfood; //扩展变量
}
-(void) eat:(int) food;//扩展方法
@end
//animal.h没有改变只改变了animal.m
// animal.m
#import "animal.h"
#import "animal_extention.h"
@implementation animal
-(void) run
{
NSLog(@"the animal is running");
}
-(void) printleg
{
NSLog(@"the animal has %d legs",_leg);
}
-(void) eat:(int) food //扩展方法
{
maxfood = food;
NSLog(@"动物的食量是%d",maxfood);
}
@end
运行结果:
由例3可知,扩展的变量是相对私有变量,不能被继承,只能被当前类实用。
如果将扩展的声明和实现全部定在原类的.m中那么扩展的方法也是私有的。