OC中不支持多继承和抽象类,因而出现了协议。其实就是把一个某一系列相同功能类应该实现的方法定义在协议中,编写类的时候遵守这个协议,那么也意味着该类应该实现对应的方法。
在iOS编程实践中,协议的比较总要的两个应用场景是:
- 实现代理设计模式
- 实现protocol形式的项目组件化
基本语法
协议也可以继承协议
@protocol <#protocol name#> <NSObject>
<#methods#>
@end
代理模式
定义一套接口,某对象若想接受另一个对象的委托,则需遵从此接口,以便成为它的代理。之后委托者可以向代理请求数据,或者发出事件回调。
比较经典的使用是UITableView。对于一个视图而言,它的内部应该仅包含一定数据源格式时视图如何展示的逻辑。而不应该包括数据和交互逻辑。所以将数据的获取组装作为一个数据源代理(data source),把与视图的交互反馈作为代理(delegate)。最终实现数据与业务逻辑的解耦。
另外一个场景是网络获取数据,Effect Objective-C中有这样一个例子:
代理的属性修饰
代理的属性修饰符应该使用weak,复合语义,因为委托方并不持有代理,两者生命周期无关。并且也避免了引用,因为代理一般会持有委托方。
@optional和@required
@optional用来定义可选协议方法,默认是可选的。@required用来定义必须实现的协议方法。
可以使用respondsToSelector来判断代理是否能够响应协议方法。
使用位段(bitfield)来缓存响应能力
位段的实现:
struct {
unsigned int didReceiceData :1;
unsigned int didFailWithError :1;
} _delegateFlags;
这里每一个值可以存储0或1,在设置代理时通过respondsToSelector赋值,以后使用的时候判断缓存值即可。
一个例子
--------------- interface 文件 ---------------
#import <Foundation/Foundation.h>
@class FTMNetworkFetcher;
@protocol FTMNetworkFetcherDelegate <NSObject>
@optional
- (void)networkFetcher:(FTMNetworkFetcher *)fetcher
didReceiveData:(NSData *)data;
- (void)networkFetcher:(FTMNetworkFetcher *)fetcher
didFailWithError:(NSError *)error;
@end
@interface FTMNetworkFetcher : NSObject
@property (weak, nonatomic) id<FTMNetworkFetcherDelegate> delegate;
@end
--------------- implementation 文件 ---------------
#import "FTMNetworkFetcher.h"
@interface FTMNetworkFetcher () {
struct {
unsigned int didReceiceData :1;
unsigned int didFailWithError :1;
} _delegateFlags;
}
@end
@implementation FTMNetworkFetcher
- (void)setDelegate:(id<FTMNetworkFetcherDelegate>)delegate {
_delegate = delegate;
_delegateFlags.didReceiceData = [_delegate respondsToSelector:@selector(networkFetcher:didReceiveData:)];
_delegateFlags.didFailWithError = [_delegate respondsToSelector:@selector(networkFetcher:didFailWithError:)];
}
@end