类别(分类)

类别(分类)
1. 为什么要使用分类
问题:需要为已经存在的类添加新的功能,但是又不想为此创建子类。
1)比如,如果需要为NSString添加一个功能,创建NSString类的子类将非常麻烦(因为NSString使用了底层的“类簇”)
2)比如,需要为某个图像类UIImage添加一个网络加载图片的功能,但是仅为了该功能就创建一个子类,就不是很方便。因为任何想要使用该功能的图像对象,必须定义成这个子类类型,而不能定义成通用的UIImage类型,在使用上不方便。

解决方案:使用分类

  1. 分类的使用
    分类的作用
    分类,用来给已有的类添加新的方法。
    分类,可以为任何已有的类添加方法,甚至可以为没有源代码的类添加方法。

分类的局限性
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

  1. 分类中不能定义实例变量
    类扩展中可以定义实例变量

  2. 文件的组织方式不同
    分类的实现部分@implementation一般都放在自己独立的.m文件中。
    类扩展的实现部分则必须放到已有类的@implementation中。

    类扩展的@interface部分可以放在独立的 .h文件中,
    一般都放在已有类的.m文件中。

  3. 分类中定义的属性、方法都是public的
    类扩展中定义的属性、方法、都是private的
    注:类扩展中,很少定义方法。
    因为可以直接在原有类的@implementation中定义私有方法。

  4. 使用目的不同
    分类用于给已有类添加public功能。
    类扩展是为了在类的内部添加实例变量、属性、方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值