Protocol in Objective-C
前面提到了OOP的继承,但不像C++可以有多重继承,Objective-C是单一继承的,如果想要做到一个类别同时拥有多种型别的能力,可以透过实作其它型别的interface来达成这个目的。在Java/AS3是用”interface”这个关键字,在Objective-C则是用”@protocol”。(有写过Java/AS3的要特别注意不要把interface跟protocol搞混了,在Objective-C的interface等于Java/AS3的class,而protocol则是相当于interface)
直接来看看要怎么做吧。如果你要新增一个自定的protocol的话,可以直接在你的专案里新增一个protocol档:
当然,你要全部写在一起也没人反对,只是为了模组化以及以后的可重复使用考量,建议独立出来另外写。新增完成之后(它是一个header档),就可以开始来写了,程式码如下:
1
2
3
4
5
6
| @protocol Drawable
-(void) draw;
-(void) changeColor;
@end
|
在Objective-C里的protocol是用@protocol 这个语法来定义的。在上面这段程式码里,我放了两个方法,但没有写内容。接下来如果我要实作自这个protocol的话,所有定义在@protocol里的方法都得实作出来。另外,在Objective-C 2.0之后加了@required 跟@optional 的语法,可以让你设定这个method是不是必需一定要实作的项目。用法如下:
1
2
3
4
5
6
7
8
9
10
| @protocol Drawable
@required
-(void) draw;
-(void) changeColor;
@optional
-(void) whateverMethod;
@end
|
如果没特别标明的,预设是@required。如果你要实作这个protocol的话,照英文字面来看,@required的部份是规定要实作的,@optional的话就随你高兴了。要注意的是@required跟@optional这两个语法的影响范围,是从它以下所有的method都会被影响,直到另一个directive或是@end为止,所以如果你要省略@required的话,记得那些method要写在@optional前面。接下来来看看要怎么实作这个protocol:
1
2
3
4
5
6
7
8
9
10
| #import <Cocoa/Cocoa.h>
#import "Drawable.h"
@interface Book : NSObject <Drawable>
{
int price;
}
@property int price;
@end
|
实作protocol的方法就是用”<>”标记,里面放protocol的名称。并不限定只能实作一个protocol,如果要实作多个protocol的话,则是用逗点分开:
1
| @interface Book : NSObject <Drawable, Openable>
|
因为到目前为止,我们都还没实作那个protocol里定义的方法,所以这时候如果直接按下Build的话,就会跳出警告讯息:
接着来把该做的填一填吧。因为在protocol的地方已经有定义好了方法,所以在@interface的地方就不用再特别写一次,只要在@implementation里补上该实作的方法就行了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| // --------------
// interface
// --------------
#import <Cocoa/Cocoa.h>
#import "Drawable.h"
@interface Book : NSObject <Drawable>
{
int price;
}
@property int price;
@end
// --------------
// implementation
// --------------
#import "Book.h"
@implementation Book
@synthesize price;
// 实作方法draw
-(void) draw
{
NSLog(@"draw me!");
}
// 实作方法changeColor
-(void) changeColor
{
NSLog(@"change color!");
}
@end
|
如果你实作了所有@required的方法的话,则称为遵守(conform)或采纳(adopt)这个protocol(硬翻成中文还是觉得怪怪的,还是英文比较简洁直接)。若要检查某物件是否有乖乖遵守某个protocol的规定:
1
2
3
4
5
| Book *book = [[Book alloc] init];
if ([book conformsToProtocol:@protocol(Drawable)] == YES)
{
NSLog(@"the book is conform to Drawable protocol");
}
|
protocol本身也可以像一般类别的继承,例如:
1
2
3
4
5
6
7
| @protocol A
-(void) methodA;
@end
@protocol B <A>
-(void) methodB;
@end
|
这时如果你要实作protocol B,则methodA跟methodB都需要实作。
另外,你也可以把protocol拿来当一般的型别定义来用,例如:
1
| id <Drawable> some_object;
|
表示说这个some_object是个有实作Drawable这个protocol的物件,在编译阶段就可以先做型别检查。当然也可以一次多个,一样用逗点分开:
1
| id <Drawable, Openable> some_object;
|
上面提到的这种用@protocol来定义方法的,称做formal protocol ,从名字看大概猜得出来一定也有叫做informal protocol 的东西,不过这个会在category的部份再做说明。
|