4

在使用架构模式时,使用Objective-Cwhich 是传递对象的首选方法DataManagerInteractorVIPER

特别是使用Block Based Callbacksvs. aDataManager Output Protocol

VIPER上最初的 Mutual Mobile 文章中示例待办事项应用程序

Block Based Callbacks像这样使用

- (void)todoItemsBetweenStartDate:(NSDate *)startDate endDate:(NSDate *)endDate completionBlock:(void (^)(NSArray *todoItems))completionBlock;

而来自 Brigade Engineering 的这种方法

利用OutputProtocol一个DataManager

[self.interactor foundUser:user];

哪种方法更好,为什么?

注意:我知道在使用 Swift 时,闭包可以使回调方法更简洁。这个问题直接参考了Objective-C。

4

2 回答 2

4

我倾向于尽可能使用输出协议,因为它使测试更容易。当只有一个侦听器时,使用输出协议会更容易。如果有多个监听器,使用回调块更容易,这样对象就不必为每个请求跟踪接收者。

我发现输出协议更容易测试,因为您可以直接调用侦听器。例如,Presenter 通常实现 Interactor 的输出协议。假设我们的登录交互器输出协议有两种方法:

- (void)didLogin - (void)loginFailedWithError:(NSError*)error

在测试 Login Presenter 时,我们将要编写登录成功和登录失败的测试。登录成功的测试可以直接调用[presenter didLogin];,失败的测试可以直接调用[presenter loginFailedWithError:badCredentialsError];

相反,如果我们使用了回调块,登录交互器接口可能类似于:

- (void)loginWithUsername:(NSString*)username password:(NSString*)password result:(void (^)(NSError* error))block;

在测试 Presenter 时,要测试成功案例,您需要存根 Interactor 登录方法以返回成功,然后调用 Presenter 上的一个方法,强制它向 Interactor 发出登录请求。

[interactor willSucceed]; [presenter login];

这使您的测试对实际意图不太清楚。

如果您可以设计您的 DataManager API 以支持输出协议,它将使测试更容易。如果没有,我不会担心,只需使用回调块。

于 2016-02-09T17:03:27.297 回答
1

这不是一刀切,而是:

  1. 如果只有一个回调,则倾向于支持完成块。
  2. 如果存在相关回调系列,则倾向于使用协议/委托。

您可能还可以使用其他启发式方法(例如,如果可能有一个明显的对象来实现协议并且只需要实现一次,那么委托会更好)。

您会看到两者都在 Apple 的框架中使用。在块之前,有更多使用目标/选择器的调用——我会说永远不要使用它(改用块)

于 2016-02-09T14:34:21.067 回答