// Box.m
#import "Box.h"
@implementation Box
// ...省略代码
- (void) print:(id<Printable>)pObj {
[pObj print];
}
// ...省略代码
@end
谈一些个人的观点,感觉在Objective-C中的通常用来创建类的@interface反而不像传统意义上的接口,更像是类的提纲。
本文所提及的协议则更像传统意义上的接口。
分析以下情况
// Printable.h
#import <Foundation/Foundation.h>
@protocol Printable <NSObject>
- (void) print;
@end
// Drawable.h
#import <Foundation/Foundation.h>
@protocol Drawable <NSObject>
- (void) draw;
@end
// Box.h
#import <Foundation/Foundation.h>
@interface Box <Drawable, Printable>
{
double width;
double height;
}
- (double) area;
- (void) print;
- (void) draw;
@end
// Box.m
#import "Box.h"
@implementation Box
- (double) area {
return width * height;
}
- (void) print {
NSLog(@"I am instance of Box -> w:%g h:%g", widht, height);
}
- (void) draw {
NSLog(@"Box -> Draw");
}
@end
上例中Box类遵循了两套协议Drawable和Printable
所以在@implementation阶段需要实现这两个协议中的方法来遵守协议
这样看来是不是更像传统意义上的接口?
但这里其实就算在@implementation阶段不实现接口编译照样可以通过,只是回得到一个警告,告诉你Box还有未实现的方法,不遵守协议的代价相当小。
甚至如果没有实现Box的@interface的所有方法依然可以编译通过,但一个类可以遵循多个协议。
在@protocol中可以使用@require指令和@optional指令来说明该接口是否应该被遵循。不加指令默认是@require的。
上面的Printable协议与下面等价
#import <Foundation/Foundation.h>
@protocol Printable <NSObject>
@required
- (void) print;
@end
而所说的非正式协议则指的是包含在@optional指令中的方法,比如随便在Printable中加一些required和optional的方法
#import <Foundation/Foundation.h>
@protocol Printable <NSObject>
@required
- (void) print;
- (void) foo;
- (void) bar;
@optional
- (void) foobar;
- (void) barfoo;
@end
很明显print/foo/bar为必须实现,不实现的代价就是警告
而foobar/barfoo则可选实现,不实现连警告都不会出现
如果一个协议仅包含@optional部分则这个协议便是传说中的非正式协议
在定义某个方法时可以指定这个方法只接受遵循某种协议的参数,类似给Box增加一个类方法print
// Box.h
#import <Foundation/Foundation.h>
@interface Box <Drawable, Printable>
// ...省略代码
+ (void) print:(id<Printable>)pObj;
// ...省略代码
@end
// Box.m
#import "Box.h"
@implementation Box
// ...省略代码
+ (void) print:(id<Printable>)pObj {
[pObj print];
}
// ...省略代码
@end
在参数类型中采用(id<Protocol>)来说明该参数遵循了哪个协议
在方法体中则直接可以调用该对象的协议内方法,而无需关心这个pObj是一个Box还是一个Circle
虽然这个print的方法设计不太合理,但纯粹是演示之用。