四、协议

2018-01-25  本文已影响9人  faterman

OC中不支持多继承和抽象类,因而出现了协议。其实就是把一个某一系列相同功能类应该实现的方法定义在协议中,编写类的时候遵守这个协议,那么也意味着该类应该实现对应的方法。
在iOS编程实践中,协议的比较总要的两个应用场景是:

基本语法

协议也可以继承协议

@protocol <#protocol name#> <NSObject>

<#methods#>

@end

代理模式

定义一套接口,某对象若想接受另一个对象的委托,则需遵从此接口,以便成为它的代理。之后委托者可以向代理请求数据,或者发出事件回调。

比较经典的使用是UITableView。对于一个视图而言,它的内部应该仅包含一定数据源格式时视图如何展示的逻辑。而不应该包括数据和交互逻辑。所以将数据的获取组装作为一个数据源代理(data source),把与视图的交互反馈作为代理(delegate)。最终实现数据与业务逻辑的解耦。

另外一个场景是网络获取数据,Effect Objective-C中有这样一个例子:


image.png

代理的属性修饰

代理的属性修饰符应该使用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
上一篇下一篇

猜你喜欢

热点阅读