3

我从 ReactiveCocoa 开始。简单的事情是有道理的,但我还不能做复杂的事情。;)

这就是我要建模的内容:我有一个视图控制器,它显示从 HTTP 端点请求的一些数据。HTTP 端点使用类似于浏览器的基本身份验证和 cookie。

所以,我想发出那个 HTTP 请求。如果成功,很好,显示数据。如果它以 401 失败,我需要告诉视图弹出一个模式对话框,询问用户名/密码,然后重试 HTTP 请求。

那么,在我的 ViewModel 中,我有两个信号吗?一个返回内容,另一个告诉视图层我需要凭据?如何将凭据返回到 HTTP 请求发生的位置?

4

1 回答 1

9

您的 ViewModel 使您的应用程序的模型适应它的视图。换句话说,它维护视图需要显示的任何状态(以可绑定属性的形式)并公开 API 以更新该状态并执行应用程序的“工作”(以普通旧方法的形式)。所以,从你写的来看:

“我有一个视图控制器,它显示从 HTTP 端点请求的一些数据。”

听起来好像是,您的 ViewModel 应该有某种方式将这些数据表示为状态。这几乎总是可以使用 Objective-C 属性来完成:

@interface MyViewModel : NSObject
@property (nonatomic, strong) NSArray *tableData;
// (Or whatever makes sense for your view.)
@property (nonatomic) BOOL needCredentials;
@end

然后,您的视图控制器应该绑定到这些属性,以便每当属性更改时(例如,每当检索到新数据或收到 401 错误时),相应的 UIView 都会更新。请注意您的 ViewModel 的 API 甚至没有任何 ReactiveCocoa 代码。那是因为如果您的视图控制器具有对 ViewModel 对象的引用,则视图控制器可以使用 ReactiveCocoa 以任何有意义的方式绑定到 ViewModel。例如,在更简单的情况下,您可以只使用RAC(self, infoView.name) = RACObserve(self, myViewModel.infoViewName);. 在更复杂的情况下,例如实现 UITableViewDelegate,您将需要实现 UITableViewDataSource 方法,但这是相同的想法。要显示询问用户名和密码的模式对话框,您甚至可以使用类似

- (void)viewDidLoad
{
    self.myViewModel = [[ViewModel alloc] init];
    @weakify(self);
    [[RACObserve(self, myViewModel.needCredentials) ignore:@NO] subscribeNext:^(id _) {
        @strongify(self);
        [self displayModalDialog];
    }];
}

“所以,我想发出那个 HTTP 请求。如果成功,很好,显示数据。如果失败并显示 401,我需要告诉视图弹出一个模式对话框,询问用户名/密码,然后重试HTTP 请求。”

您的 ViewModel 可能有一个方法,例如- (void)sendRequest:(NSDictionary *)parameters. 从视图控制器调用此方法可能如下所示:

- (IBAction)handleButtonTap:(id)sender
{
    NSDictionary *parameters = [self makeParametersFromTextFields];
    [self.myViewModel sendRequest:parameters];
}

再次注意:ViewModel 的 API 中不需要 ReactiveCocoa 代码。这并不是说您不应该使用 RAC,只是 ViewModel 的 API不一定依赖于信号或任何 ReactiveCocoa 概念——它只是一个模型对象,专门用于为您的应用程序中的特定视图提供服务。在 ViewModel 的方法实现中,您可能会到处使用信号,或者您可能正在使用一些更命令式的 API,例如 NSOperationQueues 或其他东西。这并不重要,只要您的 ViewModel 通过 KVO-observable 属性向视图公开数据(以便您的视图控制器可以绑定到这些属性,这通常使用 ReactiveCocoa 完成)。

那么你的-sendRequest:方法对这个参数字典做了什么?我不知道。那部分取决于你。如果它得到有效响应,您应该更新 ViewModel 上的某些属性(例如,tableData上面代码片段中的属性)。如果它得到一个401,它应该更新 ViewModel 上的一些其他属性(例如,将needCredentials属性设置为YES)。已经将自身绑定到这些属性的视图控制器将以您配置的任何方式做出反应。

“那么,在我的 ViewModel 中,我有两个信号吗?一个返回内容,另一个告诉视图层我需要凭据?如何将凭据返回到 HTTP 请求发生的位置?”

我希望到目前为止我已经回答了这个问题。ViewModel 不需要任何信号。它只需要支持 KVO 的属性。正如上面-handleButtonTap:方法示例中所展示的,您不需要做任何特殊的事情来获取发生 HTTP 请求的凭据——只需调用 ViewModel 上的方法,并传递任何有意义的数据。(当然,ViewModel 必须知道将凭据提供给哪个对象才能启动 HTTP 请求并处理响应,但这部分应该是相当学术的。)

于 2013-12-28T02:15:11.670 回答