类别(分类)
类别(分类)
1. 为什么要使用分类
问题:需要为已经存在的类添加新的功能,但是又不想为此创建子类。
1)比如,如果需要为NSString添加一个功能,创建NSString类的子类将非常麻烦(因为NSString使用了底层的“类簇”)
2)比如,需要为某个图像类UIImage添加一个网络加载图片的功能,但是仅为了该功能就创建一个子类,就不是很方便。因为任何想要使用该功能的图像对象,必须定义成这个子类类型,而不能定义成通用的UIImage类型,在使用上不方便。
解决方案:使用分类
- 分类的使用
分类的作用
分类,用来给已有的类添加新的方法。
分类,可以为任何已有的类添加方法,甚至可以为没有源代码的类添加方法。
分类的局限性
1)在分类中,不能添加实例变量
2)在分类中,可以添加属性,
但是不能在分类的implementation中使用@synthesize stringCount进行“属性合成”。
注意,在分类中定义的属性,
不会自动生成实例变量、getter以及setter方法
3)如果分类中定义的方法和原有类的方法同名,则使用分类中的方法。
即,分类中的名法的优先级更高。
分类的格式
和普通类的定义相似,
接口部分:
@interface 类名(分类名)
……
@end
实现部分:
@implementation 类名(分类名)
……
@end
分类的文件名的命名规则
分类的文件名可以任意定义,
但是通常命名为 “类名+类别.h”, “类名+类别.m”
分类的使用:
包含分类的头文件后,使用对应的普通类即可。
Demo
给汽车类创建一个分类, 实现充电功能
Car+Charge.h
import “Car.h”
@interface Car (Charge)
- (void)carCharge;
@end
Car+Charge.m
import “Car+Charge.h”
@implementation Car (Charge)
- (void)carCharge
{
NSLog(@”充电…”);
}
@end
main.m
import “Car.h”
import “Car+Charge.h” //包含分类的头文件
int main(int argc, const char * argv[]) {
@autoreleasepool {
Car *car = [Car new];
[car carCharge]; //直接使用分类中的方法carCharge
}
return 0;
}
3.1 拆分类的实现文件(implementation部分)
问题:
类的实现部分,必须在同一个文件中。
如果某个类的功能很多,实现文件将非常庞大,不便于该类的维护。
解决方案:
用分类把类的实现“分散”到多个文件中。
可以把这个类按照不同功能,拆分到多个分类中实现。
各个分类的@interface部分(接口部分)都放到该类的.h文件中。
各个分类的@implementation部分(实现部分)则放到各自的.m文件中。
Demo
CategoryThing类
//CategoryThing.h
//类CategoryThing的接口
@interface CategoryThing : NSObject
{
NSInteger thing1;
NSInteger thing2;
NSInteger thing3;
}
@end // CategoryThing
//分类Thing1的接口
@interface CategoryThing (Thing1)
- (void)setThing1:(NSInteger)thing1;
- (NSInteger)thing1;
@end // CategoryThing (Thing1)
//分类Thing2的接口
@interface CategoryThing(Thing2)
- (void)setThing2:(NSInteger)thing2;
- (NSInteger)thing2;
@end // CategoryThing (Thing2)
//分类Thing3的接口
@interface CategoryThing (Thing3)
- (void)setThing3:(NSInteger)thing3;
- (NSInteger)thing3;
@end // CategoryThing (Thing3)
//CategoryThing.m
import “CategoryThing.h”
@implementation CategoryThing
- (NSString *)description
{
NSString *desc = [NSString stringWithFormat: @”%d %d %d”,
thing1, thing2, thing3];
return (desc);
}
@end
分类Thing1的实现
Thing1.m
import “CategoryThing.h”
@implementation CategoryThing (Thing1)
- (void)setThing1:(NSInteger)t1
{
thing1 = t1;
}
- (NSInteger) thing1
{
return (thing1);
}
@end
分类Thing2的实现
Thing2.m
import “CategoryThing.h”
@implementation CategoryThing (Thing2)
(void)setThing2:(NSInteger) t2
{
thing2 = t2;
}(NSInteger)thing2
{
return (thing2);
}
@end // CategoryThing
分类Thing3的实现
Thing3.m
import “CategoryThing.h”
@implementation CategoryThing (Thing2)
(void)setThing3:(NSInteger) t3
{
thing3 = t3;
}(NSInteger)thing3
{
return (thing3);
}
@end
3.2 用分类声明已有类的私有方法
注意:该方式仅限于在开发阶段用于调试某些功能。
代码中使用该方式,将不能通过苹果公司的审核,无法上架。
类的私有方法
类的@interface中声明的方法,是用来给他人使用的。
但是在类的内部实现时,常常需要定义很多仅限于内部使用的方法。
仅只能在类的方法中调用,不同通过对象调用。
在@implementation部分中定义的方法都是私有方法。
调用类的私有方法
直接通过对象调用私有方法,将不能通过编译。
解决方案:
1)通过选择器@select调用。
Demo
假设Car类中有私有方法test
Car *car = [Car new];
//[car test]; error, 无法通过编译, 在car的Interface中没有找到test方法
[car performSelector:@selector(test) withObject:nil]; //绕过编译检查,直接调用”私有”方法
2)在分类中声明私有方法
代码中使用该方式,将不能通过苹果公司的审核,无法上架。
仅限于开发、调试阶段使用。
4.类扩展
类扩展,即“匿名分类”。
类扩展和分类的比较
1)类扩展在形式上和分类相似,只是没有分类的名称
@interface 类名()
……
@end
分类中不能定义实例变量
类扩展中可以定义实例变量文件的组织方式不同
分类的实现部分@implementation一般都放在自己独立的.m文件中。
类扩展的实现部分则必须放到已有类的@implementation中。类扩展的@interface部分可以放在独立的 .h文件中,
一般都放在已有类的.m文件中。分类中定义的属性、方法都是public的
类扩展中定义的属性、方法、都是private的
注:类扩展中,很少定义方法。
因为可以直接在原有类的@implementation中定义私有方法。使用目的不同
分类用于给已有类添加public功能。
类扩展是为了在类的内部添加实例变量、属性、方法。