当前位置:K88软件开发文章中心编程语言Objective-CObjective-C01 → 文章内容

Protocols

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-10 11:12:19

由 
如此轻盈 
创建,
最后一次修改 
2016-08-12 Protocols在 Objective-C 的世界里面经常错过的一个东西是抽象接口。
接口(interface)这个词通常指一个类的 .h 文件,
但是它在 Java 程序员眼里有另外的含义: 一系列不依赖具体实现的方法的定义。
在 Objective-C 里是通过 protocol 来实现抽象接口的。
因为历史原因,
protocol (作为 Java 接口使用)并没有在 Objective-C 社区里面广泛使用。
一个主要原因是大多数的 Apple 开发的代码没有包含它,
而几乎所有的开发者都是遵从 Apple 的模式以及指南的。
Apple 几乎只是在委托模式下使用 protocol。
但是抽象接口的概念很强大,
它计算机科学的历史中就有起源,
没有理由不在 Objective-C 中使用。
我们会解释 protocol 的强大力量(用作抽象接口),
用具体的例子来解释:把非常糟糕的设计的架构改造为一个良好的可复用的代码。
这个例子是在实现一个 RSS 订阅的阅读器(它可是经常在技术面试中作为一个测试题呢)。
要求很简单明了:把一个远程的 RSS 订阅展示在一个 tableview 中。
一个幼稚的方法是创建一个 UITableViewController 的子类,
并且把所有的检索订阅数据,
解析以及展示的逻辑放在一起,
或者说是一个 MVC (Massive View Controller)。
这可以跑起来,
但是它的设计非常糟糕,
不过它足够过一些要求不高的面试了。
A minimal step forward would be to follow the Single Responsibility Principle and create at least 2 components to do the different tasks:最小的步骤是遵从单一功能原则,
创建至少两个组成部分来完成这个任务:一个 feed 解析器来解析搜集到的结果一个 feed 阅读器来显示结果这些类的接口可以是这样的:@interface ZOCFeedParser : NSObject@property (nonatomic, weak) id <
ZOCFeedParserDelegate>
delegate;
@property (nonatomic, strong) NSURL *url;
- (id)initWithURL:(NSURL *)url;
- (BOOL)start;
- (void)stop;
@end@interface ZOCTableViewController : UITableViewController- (instancetype)initWithFeedParser:(ZOCFeedParser *)feedParser;
@endZOCFeedParser 用一个 NSURL 来初始化来获取 RSS 订阅(在这之下可能会使用 NSXMLParser 和 NSXMLParserDelegate 创建有意义的数据),
ZOCTableViewController 会用这个 parser 来进行初始化。
我们希望它显示 parser 接受到的指并且我们用下面的 protocol 实现委托:@protocol ZOCFeedParserDelegate <
NSObject>
@optional- (void)feedParserDidStart:(ZOCFeedParser *)parser;
- (void)feedParser:(ZOCFeedParser *)parser didParseFeedInfo:(ZOCFeedInfoDTO *)info;
- (void)feedParser:(ZOCFeedParser *)parser didParseFeedItem:(ZOCFeedItemDTO *)item;
- (void)feedParserDidFinish:(ZOCFeedParser *)parser;
- (void)feedParser:(ZOCFeedParser *)parser didFailWithError:(NSError *)error;
@end用合适的 protocol 来来处理 RSS 非常完美。
view controller 会遵从它的公开的接口:@interface ZOCTableViewController : UITableViewController <
ZOCFeedParserDelegate>
最后创建的代码是这样子的:NSURL *feedURL = [NSURL URLWithString:@"http://bbc.co.uk/feed.rss"];
ZOCFeedParser *feedParser = [[ZOCFeedParser alloc] initWithURL:feedURL];
ZOCTableViewController *tableViewController = [[ZOCTableViewController alloc] initWithFeedParser:feedParser];
feedParser.delegate = tableViewController;
到目前你可能觉得你的代码还是不错的,
但是有多少代码是可以有效复用的呢?view controller 只能处理 ZOCFeedParser 类型的对象: 从这点来看我们只是把代码分离成了两个组成部分,
而没有做任何其他有价值的事情。
view controller 的职责应该是“从上显示一些内容”,
但是如果我们只允许传递ZOCFeedParser的话就不是这样的了。
这就表现了需要传递给 View controller 一个更泛型的对象的需求。
We modify our feed parser introducing the ZOCFeedParserProtocol protocol (in the ZOCFeedParserProtocol.h file where also ZOCFeedParserDelegate will be).我们使用 ZOCFeedParserProtocol 这个 protocol (在 ZOCFeedParserProtocol.h 文件里面,
同时文件里也有 ZOCFeedParserDelegate )@protocol ZOCFeedParserProtocol <
NSObject>
@property (nonatomic, weak) id <
ZOCFeedParserDelegate>
delegate;
@property (nonatomic, strong) NSURL *url;
- (BOOL)start;
- (void)stop;
@end@protocol ZOCFeedParserDelegate <
NSObject>
@optional- (void)feedParserDidStart:(id<
ZOCFeedParserProtocol>
)parser;
- (void)feedParser:(id<
ZOCFeedParserProtocol>
)parser didParseFeedInfo:(ZOCFeedInfoDTO *)info;
- (void)feedParser:(id<
ZOCFeedParserProtocol>
)parser didParseFeedItem:(ZOCFeedItemDTO *)item;
- (void)feedParserDidFinish:(id<
ZOCFeedParserProtocol>
)parser;
- (void)feedParser:(id<
ZOCFeedParserProtocol>
)parser didFailWithError:(NSError *)error;
@end注意这个代理 protocol 现在处理响应我们新的 protocol 而且 ZOCFeedParser 的接口文件更加精炼了:@interface ZOCFeedParser : NSObject <
ZOCFeedParserProtocol>
- (id)initWithURL:(NSURL *)url;
@end因为 ZOCFeedParser 实现了 ZOCFeedParserProtocol,
它需要实现所有需要的方法。
从这点来看 view controller 可以接受任何实现这个新的 protocol 的对象,
确保所有的对象会响应从 start 和 stop 的方法,
而且它会通过 delegate 的属性来提供信息。
所有的 view controller 只需要知道相关对象并且不需要知道实现的细节。
@interface ZOCTableViewController : UITableViewController <
ZOCFeedParserDelegate>
- (instancetype)initWithFeedParser:(id<
ZOCFeedParserProtocol>
)feedParser;
@end上面的代码片段的改变看起来不多,
但是有了一个巨大的提升。
view controller 是面向一个协议而不是具体的实现的。
这带来了以下的优点:view controller 可以通过 delegate 属性带来的信息的任意对象,
可以是 RSS 远程解析器,
或者本地解析器,
或是一个读取其他远程或者本地数据的服务ZOCFeedParse

[1] [2]  下一页


Protocols