Objective-C的面向对象特性(二)

时间:2022-10-22 07:34:12

在Objective-C语言中, 类别、类扩展(也称为匿名类别)以及协议是Objective-C 语言级别支持的模式,用来实现对类进行功能扩展。

一、类别--用来增加方法到已存在类

声明一个类别的语法如下:

@interface ClassName (CategoryName)

@end

Objective-C 的标准的类声明,也使用@interface 关键字。但类别与类声明区别的是在括号中声明了一个类别名字。

类别能为任何类添加类别,包括不知道源代码的类(例如标准的Cocoa Touch 类等)。

已声明类别的类,类及其子类的所有实例都可以使用声明在类别中的方法,在运行时,通过类别为类添加的方法与类本身的方法没有任何区别。

类别也通常在头文件中进行声明,在分离的源文件中进行类别方法的实现。

为了使用为类添加的类别,需要在使用的地方输入声明类别的头文件。

类别可以作为一种设计模式使用,用来使用类别把一个实现复杂的类分离为几个实现文件。也可以为不同的平台提供不同的类别实现方法。

类别用来声明实例方法或类方法,但不适合声明额外的属性。

在一个类别接口中声明一个属性是有效的,但在类别中声明一个额外的实例变量是不可能的,这意味者编译器不能够生成任何实例变量,也不能够生成任何属性存取方法。
但你能够在类别实现中实现自己的属性存取方法,但你不能够保持和跟踪一个属性值,除非它已经在原先的类中存储。

另外需要注意的是类别中定义的方法名字不能与该类已有的方法或为该类(或其超类)定义的其它类别中的方法冲突。

为已存在类添加带有实例变量的属性的仅有的方法是使用类扩展。

二、类扩展--用来扩展一个类的内部实现

类扩展功能上与类别类似,用来扩展一个类的功能,与类别不同的是,类扩展中能为一个类增加属性和实例变量。另外类扩展仅能在一个有源码的类中使用,用来为其添加功能。使用类扩展通常用来实现和扩展类的私有信息(包括私有属性和方法)。

声明一个类扩展的语法与类别的语法相似,但括号中名字为空,因此类扩展也被称为匿名类别。如下所示:

@interface ClassName ()

@end

类扩展中声明的方法要在原先类的@implementation块中加以实现。

如果在一个类扩展中声明一个属性,编译器自动为其生成相对应的存取方法和一个实例变量。如果在一个类扩展中增加任意方法,它们也必须在类的实现中加以实现。

在一个类扩展中添加定制的实例变量也是可能的。

三、协议

在Objective-C中,每个类都都对外提供自己的接口,类包括接口声明和类实现。而没有像其它语言(如java)那样,接口与类定义是独立的,一个类可以实现多个接口。

但在Objective-C中协议可以起到类似的作用,协议用来声明与任何特定的类独立的方法,如果一个类声明符合某种协议,则其实现中必须实现协议中声明的方法,但与其它语言接口定义不同的是在协议中不仅能声明对象方法,还能声明类方法以及属性。

定义一个协议的语法如下:

@protocol ProtocolName

// list of methods and properties

@end

Objective-C 使用三角括号指示一个属性或类符合一种协议。

默认情况下在一个协议中声明的方法都是必须方法,任何符合该协议的类必须实现这些方法。

在协议中也可以使用@optional关键字规定可选方法。遵从包括可选方法的协议的类可以根据需要实现可选方法或不实现。

@protocol XYZPieChartViewDataSource

- (NSUInteger)numberOfSegments;

- (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;

@optional

- (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;

- (BOOL)shouldExplodeSegmentAtIndex:(NSUInteger)segmentIndex;

@required

- (UIColor *)colorForSegmentAtIndex:(NSUInteger)segmentIndex;

@end

在以上协议声明中的titleForSegmentAtIndex:和shouldExplodeSegmentAtIndex:方法标记为是可选方法。

@optional关键字指示其下面声明的方法都是可选方法,直到协议定义结束或碰到另外的@required指令。

如果在一个协议中标记一个方法为可选,你必须在试图调用它之前检查是否一个对象实现了该方法。

使用respondsToSelector: 方法使用一个@selector指令引用一个方法的标识(方法名)来检查该方法是否实现。如下所示:

NSString *thisSegmentTitle;

if ([self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)]) {

thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index];

}

也可以规定一个协议符合另外的协议,语法如下:

@protocol MyProtocol <NSObject>

...

@end

声明一个类符合一个协议的语法如下:

@interface MyClass : NSObject <MyProtocol>

...

@end

与其它语言一个类可以实现多个接口相同,在Objective-C也可以声明一个类符合多个协议,语法如下:

@interface MyClass : NSObject <MyProtocol, AnotherProtocol, YetAnotherProtocol>

...

@end

但如果出现这种情况,意味着你的类过于复杂,需要重构,分离相关的行为到多个较小的类,每一个类定义清楚的责任。