- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我刚刚开始更新我的 ReactiveCocoa 应用程序以使用 MVVM 模式,并且有几个关于 ViewController 和 ViewModel 之间的边界以及 ViewController 应该有多笨的问题。
我要更新的应用程序的第一部分是登录流程,其行为如下。
User
模型User
模型与注销按钮一起显示用户
模型。MVVM 之前
LoginViewController
直接处理LoginButton
命令LoginButton
命令直接与 SessionManager
LoginViewController
显示用于选择 User
模型或注销的 UIActionSheet
LoginViewController
的用户选择和注销功能直接与 SessionManager
对话MVVM 之后
LoginViewModel
公开登录命令以及用户选择和注销方法LoginViewModel
用户选择和注销方法直接与 SessionManager
LoginViewController
响应 LoginViewModel
LoginViewController
显示用于选择 User
模型或注销的 UIActionSheet
LoginViewController
的用户选择和注销功能与 LoginViewModel
对话LoginViewModel.h
@interface LoginViewModel : RVMViewModel
@property (strong, nonatomic, readonly) RACCommand *loginCommand;
@property (strong, nonatomic, readonly) RACSignal *checkingSessionSignal;
@property (strong, nonatomic, readonly) NSArray *users;
@property (strong, nonatomic) NSString *email;
@property (strong, nonatomic) NSString *password;
- (void)logout;
- (void)switchToUserAtIndex:(NSUInteger)index;
@end
LoginViewModel.m
@implementation LoginViewModel
- (instancetype)init {
self = [super init];
if (self) {
@weakify(self);
// Set up the login command
self.loginCommand = [[RACCommand alloc] initWithEnabled:[self loginEnabled]
signalBlock:^RACSignal *(id input) {
@strongify(self);
[[[SessionManager sharedInstance] loginWithEmail:self.email
password:self.password]
subscribeNext:^(NSArray *users) {
self.users = users;
}];
return [RACSignal empty];
}];
// Observe the execution state of the login command
self.loggingIn = [[self.loginCommand.executing first] boolValue];
}
return self;
}
- (void)logout {
[[SessionManager sharedInstance] logout];
}
- (void)switchToUserAtIndex:(NSUInteger)index {
if (index < [self.users count]) {
[[SessionManager sharedInstance] switchToUser:self.users[index]];
}
}
- (RACSignal *)loginEnabled {
return [RACSignal
combineLatest:@[
RACObserve(self, email),
RACObserve(self, password),
RACObserve(self, loggingIn)
]
reduce:^(NSString *email, NSString *password, NSNumber *loggingIn) {
return @([email length] > 0 &&
[password length] > 0 &&
![loggingIn boolValue]);
}];
}
@end
LoginViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
@weakify(self);
// Bind to the view model
RAC(self.controlsContainerView, hidden) = self.viewModel.checkingSessionSignal;
RAC(self.viewModel, email) = self.emailField.rac_textSignal;
RAC(self.viewModel, password) = self.passwordField.rac_textSignal;
self.loginButton.rac_command = self.viewModel.loginCommand;
self.forgotPasswordButton.rac_command = self.viewModel.forgotPasswordCommand;
// Respond to the login command execution
[[RACObserve(self.viewModel, users)
skip:1]
subscribeNext:^(NSArray *users) {
@strongify(self);
if ([users count] == 0) {
[Utils presentMessage:@"Sorry, there appears to be a problem with your account."
withTitle:@"Login Error"
level:MessageLevelError];
} else if ([users count] == 1) {
[self.viewModel switchToUserAtIndex:0];
} else {
[self showUsersList:users];
}
}];
// Respond to errors from the login command
[self.viewModel.loginCommand.errors
subscribeNext:^(id x) {
[Utils presentMessage:@"Sorry, your login credentials are incorrect."
withTitle:@"Login Error"
level:MessageLevelError];
}];
}
- (void)showUsersList:(NSArray *)users {
CCActionSheet *sheet = [[CCActionSheet alloc] initWithTitle:@"Select Organization"];
// Add buttons for each of the users
[users eachWithIndex:^(User *user, NSUInteger index) {
[sheet addButtonWithTitle:user.organisationName block:^{
[self.viewModel switchToUserAtIndex:index];
}];
}];
// Add a button for cancelling/logging out
[sheet addCancelButtonWithTitle:@"Logout" block:^{
[self.viewModel logout];
}];
// Display the action sheet
[sheet showInView:self.view];
}
@end
问题
SessionManager
调用。我想从 SessionManager
中解耦 LoginViewController
的好处超过了 ViewModel 层的额外代码和函数调用?LoginViewController
了解User
模型,以便显示可供选择的用户列表。这打破了 MVVM 模式,当然感觉不对。 LoginViewModel
是否应该只提取 LoginViewController
所需的 User
模型的必要属性,并将它们添加到字典中,并返回一个数组到 LoginViewController
?或者在 LoginViewModel
上有一个方法会更好,该方法返回给定索引的用户的名称,允许 LoginViewController
显示此名称?我知道 ViewModel 负责弥合模型和 View 之间的差距,但这确实感觉像是双重处理。根据我对第一个问题的直觉,我猜想将这些关注点分开的好处远远超过感觉起来有点费力的映射过程。LoginViewModel
调用包含在 SessionManager
中的所有功能,是否仅针对 LoginViewModel
编写测试就足够了,还是应该也编写测试专门针对SessionManager
?最佳答案
已经很晚了,我相信你已经继续前进了。
1) 将程序逻辑移出 View /控件始终值得您将额外的几行锥形代码写入代理。 MVVM 的要点是鼓励关注点分离,并通过 ViewModel 在 View/Controller 和 Model 之间提供清晰的数据通道。
从 View / Controller 的角度来看,您的 View 模型应该执行以下功能:
充当数据黑盒,您的 View / Controller 可以在不执行任何业务规则的情况下利用它,并始终假定数据是正确的。
充当用户输入处理的管道,无需执行任何业务规则即可获取用户输入。
2) 在我的 MVVM 实现中,我尝试遵循以下范例:包含 CollectionView/TableView 的 View / Controller 是父 View ,单元格是 subview 。因此,您应该有一个父 ViewModel,其工作是初始化和管理子 ViewModel。
在您的情况下,您没有使用集合/ TableView ,但概念是相同的。您应该向您的父 View Model 询问一个子 ViewModel 列表,您可以将其传递给另一个 View 以进行利用。根据答案 #1 中的要点,父 View 模型应确保正确初始化 subview 模型,以便 subview 无需担心任何数据验证。
3) 在测试 View 模型的数据验证/规则时,您可以完全关闭 session 管理器,只测试 View 模型。我所做的是创建断言,在我的单元测试中正确调用 stub /模拟 session 管理器函数。
关于ios - 如何在 RAC MVVM 中正确分离 ViewModel 和 ViewController,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23160777/
我已经对这个主题进行了一些研究,并且已经在少数应用程序中使用了 MVVM 模式。 我问这个问题是因为有时 MVVM 被称为设计,有时被称为架构模式。 在大多数情况下,MVVM 模式称为设计模式。但是就
我开始使用 MVVM Light 版本 4,但我无法理解: 为什么要使用 DataService 和 IDataService? 我应该为模型中的任何类创建数据服务吗? 最佳答案 首先 - 像往常一样
是否可以采用MVVM在一个平台(如 windows phone)中设计模式并以可移植到其他平台(如 android 和 iOS)的方式实现代码的数据绑定(bind)? 或者我最好问问MVVM设计模式在
使用 avalondock在 MVVM 环境中似乎相当具有挑战性。一旦我从 shellview 中分离 DocumentPane,我就会丢失相应的数据上下文并且我的 View 是空的。重新连接时,它会
我对避免背后代码中的代码的方法很感兴趣。 在我看来,有些情况下代码必须放在代码后面。 例如:我有一个未定义列数的网格。无法绑定(bind)列。所以最简单的方法是在后面的代码中生成列。 对于这种情况,我
我熟悉MVVM。实际上,我在SL4中进行了大部分学习。但是,由于最近的需求,我必须使用SL3。我试图将MVVM Light v3与SL3结合使用并利用命令。问题是在SL3中没有按钮的Command属性
UI逻辑在WindowsRT MVVM应用程序中应该在哪里?将其放到ViewModel上真的很“胖”,我想我们失去了MVVM模式的优势之一-在设计人员和程序员之间分配工作变得非常困难。但是,我创建了一
您好,我有 3 个关于 MVVM 模型的问题。 有没有办法绕过那个多余的PropertyChanged("PropName"); 将 POCO 对象包装到 WPF 的最佳方法是什么 INotifyPr
我正在使用 MVVM 模型做一个 Silverlight,我发现很难通过 MVVM 进行事件处理,尤其是事件处理程序在 View 中进行了大量更改,例如启用和禁用按钮、更新媒体元素功能和位置。我还是
我有一个测试应用程序来测试 windows phone 8.1 上的导航,我可以从主页到第二页进入第二页。 问题是,当我单击后退按钮时,我返回桌面屏幕并且应用程序进入后台,所以我必须按住后退按钮才能返
我正在尝试使用并选择好的MVVM Framework,并且其中有很多,因此选择确实很困难。 我想知道其中的2个-CinchV2(Sacha Barber)和MVVM Light Toolkit(Lau
我完全不熟悉Windows 8开发,现在遇到使用MVVM Light混合触摸和键盘导航的问题。 所以,我有个 View 模型的列表,在网格 View 和只要选择其中的一个,导航到选定的 View 模型
我最近下载了MVVMExtraLite,并且有一个名为 Mediator 的帮助程序。我听说过 Messenger (在MVVM Light中)。有什么区别吗? 最佳答案 他们使用相同的模式,即调解员
我正在尝试学习MVVM,并且在区分模型和 View 模型方面有些挣扎。 如果有人可以回答这两个问题,那么对我来说将大有帮助: 说我有一个Objects类,这是一个包含Object的多个Observab
我已经在网上进行了一些研究,并且得出了一些矛盾的答案。这是我的情况: 我有一个引用ClientViewModel的EditClient View ,还有一个还引用ClientViewModel的Add
我正在使用带有 ModelView-First 方法的 MVVM 模式。到目前为止,这工作正常。 现在我有一个用户控件( View ),它应该根据位于我的 ViewModel 中的属性显示各种内容。
我必须创建一个对话框,其中必须在运行时生成列,之前我使用的是 WPF 数据网格,因此在运行时生成列不是问题。现在我必须使用 View 模型,我需要为要在 View 中显示为列的任何字段具有属性。列数在
所以我目前正在使用 Xamarin.Forms 开发一个应用程序。 Xamarin Forms 使用 MVVM 模式,我觉得使用这种模式有点舒服,但我确实有一些问题。为了简单起见,我将使用一个单页应用
是否有在MVVM应用程序中使用Autofac的示例?我不确定在MVVM环境中如何控制生命周期和对象处置。 我知道我可以创建一个生命周期并从其下解决,但这确实更像是服务定位器模式而不是IoC模式。 最佳
我想我遗漏了一些简单的东西,但我找不到任何例子来说明如何做到这一点......另外,如果我使用的某些术语是错误的,请原谅我。 我只想使用绑定(bind)到 Kendo Observable 对象的 H
我是一名优秀的程序员,十分优秀!