我开始使用ReactiveCocoa。简单的事情是有道理的,但我还不能做复杂性。 ;)
这就是我想要建模的:我有一个视图控制器,它显示从HTTP端点请求的一些数据。 HTTP端点使用类似浏览器的基本身份验证和cookie。
所以,我想发出那个HTTP请求。如果成功,那么,显示数据。如果它失败了401,我需要告诉视图弹出一个模态对话框,询问用户名/密码,然后重试HTTP请求。
在我的ViewModel中,我有两个信号吗?一个返回内容,另一个告诉视图层我需要凭据?如何将凭据返回到HTTP请求发生的位置?
答案 0 :(得分: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请求,并处理响应,但该部分应该是非常学术的。)