oc——类——类别

概述

类别,category,是对类的implementation进行模块化设计,把implementation分散到不同的模块中
  • 允许声明Method的interface:primary class interface,extension interface,category interface
  • 允许定义Method的implementation:primary class implementation,category implementation
  • category是对类的implementation进行模块化设计,把implementation分散到不同的模块中,因此在category interface中不能定义数据成员
  • category是类的接口扩展机制,可对现有类进行接口扩展,category对现有类进行接口扩展时,无法预知现有类的所有Method,因此在category中扩展Method不可避免的会与已有Method相同(SEL相同)
  • category interface和category implementation都是optional,category interface是Method声明,category implementation是Method定义
注:oc只能确保同一interface(primary class interface或extension interface)的Method声明不重复或同一implementation(primary class implementation或category implementation)的Method定义不重复

methodLists

struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
总结:
  • objc_method_list*是方法成员list,因此同一方法成员list中,方法成员名不能重名,否则编译器不能确定使用哪个方法成员,二义性错误,或者list中优先search到的方法成员屏蔽list中之后重名方法成员(ignore之后重名方法成员),oc在编译期避免此情况发生
  • methodLists类型为objc_method_list**,即方法成员list的list,methodLists(后缀s,表示复数,多个objc_method_list*)为list,其node类型为objc_method_list*(方法成员list),methodLists之所以使用objc_method_list**类型是因为类支持类别(category),primary class和每个类别(category)的方法成员list用一个objc_method_list*(方法成员list)表示,作为methodLists的一个node,methodLists至少有一个node(objc_method_list*),存储primary class的方法成员list,之后每添加一个category,就在methodLists添加一个node(objc_method_list *),存储category的方法成员list
  • methodLists作为list,学过数据结构知道,insert node时,如果insert head,时间复杂度O(1),如果insert tail,时间复杂度O(n),显然选择insert head,因此对于methodLists,起始primary class的方法成员list(objc_method_list *)是其唯一node(head),之后添加category方法成员list(objc_method_list *),insert head,因此越后编译的category,其对应方法成员list(objc_method_list *)越在methodLists前面,越先编译的category,其对应方法成员list(objc_method_list *)越在methodLists后面,primary class总是最先编译,因此primary class的方法成员list(objc_method_list *)置于methodLists tail,方法成员调用时methodLists顺序遍历,因此置于methodLists前的Method优先被search到,而primary class的方法成员list(objc_method_list *)显然最后被search到

category

@interface FBAnimal : NSObject

- (void)feedFood1:(int)food1 andFood2:(int)food2;
- (void)feedFood3:(int)food3 andFood4:(int)food4;

@end

@implementation FBAnimal

- (void)feedFood1:(int)food1 andFood2:(int)food2
{
    NSLog(@"FBAnimal+Primary feedFood1:andFood2:");
}

- (void)feedFood3:(int)food3 andFood4:(int)food4
{
    NSLog(@"FBAnimal+Primary feedFood3:andFood4:");
}

@end

@interface FBAnimal (FeedFood56)

- (void)feedFood3:(int)food3 andFood4:(int)food4;
- (void)feedFood5:(int)food5 andFood6:(int)food6;

@end

@implementation FBAnimal (FeedFood56)

- (void)feedFood3:(int)food3 andFood4:(int)food4;
{
    NSLog(@"FBAnimal+FeedFood56 feedFood3:andFood4:");
}

- (void)feedFood5:(int)food5 andFood6:(int)food6
{
    NSLog(@"FBAnimal+FeedFood56 feedFood5:andFood6:");
}

@end

@interface FBAnimal (FeedFood78)

- (void)feedFood3:(int)food3 andFood4:(int)food4;
- (void)feedFood7:(int)food7 andFood8:(int)food8;

@end

@implementation FBAnimal (FeedFood78)

- (void)feedFood3:(int)food3 andFood4:(int)food4;
{
    NSLog(@"FBAnimal+FeedFood78 feedFood3:andFood4:");
}

- (void)feedFood7:(int)food7 andFood8:(int)food8
{
    NSLog(@"FBAnimal+FeedFood78 feedFood7:andFood8:");
}

@end
- (void)use_category
{
    FBAnimal *animal = [[FBAnimal alloc] init];
    
    [animal feedFood1:1 andFood2:2];
    [animal feedFood3:3 andFood4:4];
    [animal feedFood5:5 andFood6:6];
    [animal feedFood7:7 andFood8:8];
}
output:
FBAnimal+Primary feedFood1:andFood2:
FBAnimal+FeedFood78 feedFood3:andFood4:
FBAnimal+FeedFood56 feedFood5:andFood6:
FBAnimal+FeedFood78 feedFood7:andFood8:
调换FBAnimal (FeedFood56)和FBAnimal (FeedFood78)定义顺序,本质就是调换FBAnimal (FeedFood56)和FBAnimal (FeedFood78)编译顺序,即调换FBAnimal (FeedFood56)和FBAnimal (FeedFood78)的方法成员list(objc_method_list *)插入methodLists顺序
@interface FBAnimal : NSObject

- (void)feedFood1:(int)food1 andFood2:(int)food2;
- (void)feedFood3:(int)food3 andFood4:(int)food4;

@end

@implementation FBAnimal

- (void)feedFood1:(int)food1 andFood2:(int)food2
{
    NSLog(@"FBAnimal+Primary feedFood1:andFood2:");
}

- (void)feedFood3:(int)food3 andFood4:(int)food4
{
    NSLog(@"FBAnimal+Primary feedFood3:andFood4:");
}

@end

@interface FBAnimal (FeedFood78)

- (void)feedFood3:(int)food3 andFood4:(int)food4;
- (void)feedFood7:(int)food7 andFood8:(int)food8;

@end

@implementation FBAnimal (FeedFood78)

- (void)feedFood3:(int)food3 andFood4:(int)food4;
{
    NSLog(@"FBAnimal+FeedFood78 feedFood3:andFood4:");
}

- (void)feedFood7:(int)food7 andFood8:(int)food8
{
    NSLog(@"FBAnimal+FeedFood78 feedFood7:andFood8:");
}

@end

@interface FBAnimal (FeedFood56)

- (void)feedFood3:(int)food3 andFood4:(int)food4;
- (void)feedFood5:(int)food5 andFood6:(int)food6;

@end

@implementation FBAnimal (FeedFood56)

- (void)feedFood3:(int)food3 andFood4:(int)food4;
{
    NSLog(@"FBAnimal+FeedFood56 feedFood3:andFood4:");
}

- (void)feedFood5:(int)food5 andFood6:(int)food6
{
    NSLog(@"FBAnimal+FeedFood56 feedFood5:andFood6:");
}

@end
- (void)use_category
{
    FBAnimal *animal = [[FBAnimal alloc] init];
    
    [animal feedFood1:1 andFood2:2];
    [animal feedFood3:3 andFood4:4];
    [animal feedFood5:5 andFood6:6];
    [animal feedFood7:7 andFood8:8];
}
output:
FBAnimal+Primary feedFood1:andFood2:
FBAnimal+FeedFood56 feedFood3:andFood4:
FBAnimal+FeedFood56 feedFood5:andFood6:
FBAnimal+FeedFood78 feedFood7:andFood8:
如果把FBAnimal,FBAnimal (FeedFood56),FBAnimal (FeedFood78)的interface和implementation分别放于FBAnimal.h,FBAnimal.m,FBAnimal+FeedFood56.h,FBAnimal+FeedFood56.m,FBAnimal+FeedFood78.h,FBAnimal+FeedFood78.m,本质也一样,依赖于编译顺序,FBAnimal.m总是先编译,因为category依赖于primary class,而FBAnimal+FeedFood56.m和FBAnimal+FeedFood78.m的编译顺序则依赖于工程设置
FBAnimal+FeedFood56.m先编译,FBAnimal+FeedFood78.m后编译
output:
FBAnimal+Primary feedFood1:andFood2:
FBAnimal+FeedFood78 feedFood3:andFood4:
FBAnimal+FeedFood56 feedFood5:andFood6:
FBAnimal+FeedFood78 feedFood7:andFood8:
调换FBAnimal+FeedFood56.m和FBAnimal+FeedFood78.m的顺序
FBAnimal+FeedFood78.m先编译,FBAnimal+FeedFood56.m后编译
output:
FBAnimal+Primary feedFood1:andFood2:
FBAnimal+FeedFood56 feedFood3:andFood4:
FBAnimal+FeedFood56 feedFood5:andFood6:
FBAnimal+FeedFood78 feedFood7:andFood8:

总结

  • category是对类的implementation进行模块化设计,因此category interface不允许定义数据成员,允许声明Method
  • category interface和category implementation都是optional,category interface是Method声明,category implementation是Method定义
  • category数量无限制(可任意个),category对类进行扩展,且category的方法成员list(objc_method_list *)和primary class的方法成员list(objc_method_list *)及其它category的方法成员list(objc_method_list *)相互独立,因此只要确保同一category的方法成员不重复即可,允许与primary class的方法成员和其它category的方法成员重复,category常搭配extension扩展类的功能,extension负责定义数据成员和声明Method,category负责定义Method
  • category是对类的implementation进行模块化设计,把implementation分散到不同模块中,一般category interface放在头文件中对外open
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值