Objc在线运行

版本:
运行结果
教程手册
代码仓库
极速运行
交互输入
极速运行模式,更高效的运行,点击编辑器上方的运行按钮即刻体验吧。
以下是用户最新保存的代码
测试异常运行 发布于:2021-04-12 15:03 Objc : Core Fundation 竟然不能运行 发布于:2021-04-06 17:03 两数加减乘除,类方法 发布于:2021-03-15 20:49 Objc - 循环引用1 发布于:2021-02-26 17:13 hma_sha256脚本 发布于:2021-01-21 12:30 两数相加,类方法 发布于:2021-01-01 13:42 json 测试 发布于:2020-12-26 18:08 first objc demo 发布于:2020-08-27 18:09 first objc demo 发布于:2020-08-27 18:09 first objc demo 发布于:2020-08-27 18:07 [更多]
显示目录

Protocols



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;

@end

ZOCFeedParser 用一个 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 远程解析器,或者本地解析器,或是一个读取其他远程或者本地数据的服务

  • ZOCFeedParser 和 ZOCFeedParserDelegate 可以被其他组成部分复用

  • ZOCViewController (UI逻辑部分)可以被复用

测试更简单了,因为可以用 mock 对象来达到 protocol 预期的效果 当实现一个 protocol 你总应该坚持 里氏替换原则。这个原则让你应该取代任意接口(也就是Objective-C里的的"protocol")实现,而不用改变客户端或者相关实现。

此外这也意味着你的 protocol 不应该关注实现类的细节,更加认真地设计你的 protocol 的抽象表述的时候,需要注意它和底层实现是不相干的,协议是暴露给使用者的抽象概念。

任何可以在未来复用的设计意味着可以提高代码质量,同时也是程序员的目标。是否这样设计代码,就是大师和菜鸟的区别。

由JSRUN为你提供的Objc在线运行、在线编译工具
        JSRUN提供的Objc在线运行,Objc 在线运行工具,基于linux操作系统环境提供线上编译和线上运行,具有运行快速,运行结果与常用开发、生产环境保持一致的特点。

title

使用此草稿 删除草稿

  • 00:23
注册登录后可减少验证码的弹出,点击前往 注册 | 登录

皮肤:

运行模式:

嵌入代码 iframe嵌入: