OC——类别、扩展

一、类别

Objective-C 的动态特征允许使用类别为现有的类添加新方法,并且不需要创建子类,不需要访问原有类的源代码。通过使用类别即可动态地为现有的类添加新方法,而且可以将类定义模块化地分布到多个相关文件。


1. 类别的组成

类别由接口实现部分组成。
接口部分语法格式如下:

@interface 已有类 (类别名)
// 方法定义
...
@end

实现部分语法格式如下:

@implementation 已有类 (类别名)
// 方法实现
...
@end
  • 一般习惯将类别的接口文件命名为“类名 + 类别名.h”形式,类别实现部分的文件通常命名为“类名 + 类别名.m”的形式。
  • 通过类别为指定类添加新方法之后,这个新方法不仅会影响NSNumber类, 还会影响NSNumber类的所有子类, 每个子类都会获取类别扩展的方法。
  • 可根据需要为一个类定义多个类别, 不同的类别都可对原有的类增加方法定义。

定义类别与定义类的语法存在如下差异:

  1. 定义类时使用的类名必须是该项目中没有的类,定义类别时使用的类名必须是已有的类。
  2. 定义类别时必须使用圆括号来包含类别名。
  3. 类别中通常只定义方法。

举例:
为NSNumber 增加一个类别,类别接口部分代码如下。

// 定义一个类别
@interface NSNumber (fk)
//在类别中定义2个方法
- (NSNumber*) add: (double) num2;
- (NSNumber*) substract: (double) num2;
- @end

该类别的实现部分代码如下:

#import "NSNumber+fk.h"
//为类别提供实现部分
@implementation NSNumber (fk)
//实现类别接口部分定义的2个方法
- (NSNumber*) add: (double) num2 {
	return [NSnumber numberWithDouble: ([self doubleValue] + num2)];
}
- (NSNumber*) substract: (double) num2 {
	return [NSNumber numberWithDouble: ([self doubleValue] - num2)];
}
@end

测试 NSNumber 的 fk 类别:

#import <Foundation/Foundation.h>
#import "NSNumber+fk.h"
int main(int argc, char * argv[]) {
	@autoreleasepool {
		NSNumber* myNum = [NSNumber numberWithInt: 3];
		// 测试 add:方法
		NSNumber* add = [myNum add:2.4];
		NSLog(@"%@", add);
		//测试 substract:方法
		NSNumber* substract = [myNum substract:2.4];
		NSLog(@"%@", substract);
	}
}

2. 类别的用法

  • 利用类别对类进行模块化设计
  • 使用类别来调用私有方法
  • 使用类别来实现非正式协议

2.1 利用类别对类进行模块化设计

当某个类非常大时,如果将该类的所有实现代码放在一个文件中,将会导致这个文件非常大,以至于维护起来非常困难。利用类别对较大的类进行模块化设计的方式,对类实现按模块化分布到不同的*.m 文件中,从而提高项目后期的可维护性

2.2 使用类别来调用私有方法

没有在接口部分定义而是在类实现部分定义的方法相当于私有方法,通常不允许被调用。
但OC实际上并没有真正私有的方法,可使用NSObject 的 performSelector:方法来执行动态调用,但这完全避开了编译器的语法检查,有时候未必是种好的做法。除此之外,还可以通过类别来定义前向引用,从而实现对私有方法的调用

举例:
定义FKItem 的接口部分

#import <Foundation/Foundation.h>
@interface FKItem : NSobject
@propert (nonatomic, assign) double price;
- (void) info;
@end

FKItem实现部分如下:

#import "FKItem.h"
@implementation FKItem
@synthesize prince;
- (void) info {
	NSLog(@"这是一个普通方法")}
// 类实现部分新增的方法, 相当于私有方法
- (double) calDiscount: (double) discount {
	return self.price * discount;
}

在main()函数前 增加以下类别定义:

@interface FKItem (fk)
// 在类别中声明calDiscount:方法
- (double) calDiscount: (double)discount;
- @end

测试程序:

#import <Foundation/Foundation.h>
#import "FKItem.h"
int main(int argc, char * argv[]) {
	@autoreleasepool {
		FKTtem* item = [[FKItem alloc] init];
		item.price = 109;
		[item info];
		//calDiscount:方法仅在实现部分定义,并未在接口部分定义
		//如果没有定义以上类别,FKItem对象则不能调用calDiscount:方法
		NSLog(@"物品打折的价格为:%g", [item calDiscount:.75]);
		
	}
}

2.3 使用类别来实现非正式协议

以NSObject为基础,为NSobject创建类别,创建类别时即可指定该类别应该新增的方法。当某个类实现NSObject的该类别时,就需要实现该类别下的所有方法,这种基于NSObject定义的类别即可认为是非正式协议。


二、扩展

扩展与类别相似,相当于匿名类别,定义扩展的语法格式如下:

@interface 已有类 ()
{
	实例变量
}
//方法定义
...
@end

与类别的不同处

  • 类别通常由单独的X.h 和 X.m文件,扩展则用于临时对某个类的接口进行扩展,类实现部分同时实现类接口部分定义的方法和扩展中定义的方法
  • 类的扩展,可以额外增加实例变量,也可以使用@property 来合成属性,定义类的类别时,则不允许额外定义实例变量,也不能合成属性。

猜你喜欢

转载自blog.csdn.net/qq_45836906/article/details/106924563
今日推荐