对 MVVM 中的信号做出反应?
Reacting to a Signal in MVVM?
我第一次设置登录视图和使用响应式编程时 - 我无法从我的 ViewContoller 生成一个信号,该信号将在我的视图中使用包含我的表单验证的 Bool 提醒我的 observeValues
侦听器:
查看文件
viewModel.outputs.loginSuccess
.observeValues { [weak self] value in
print(value)
}
使用我当前的代码 loginSuccess
每次更改电子邮件或密码文本字段时都会触发(我的视图文件中有 .addTarget
用于更新我的模型视图文件中的 MutableProperites) .我遇到麻烦的地方是为 tryLogin
创建一个信号,该信号仅在按下登录按钮时发出,然后映射我的表单验证( emailAndPassword.map(isValid)
),我可以在我的视图文件中对其进行响应。
模型视图文件
import ReactiveCocoa
import ReactiveSwift
import Result
public protocol LoginViewModelInputs {
/// String value of email textfield text
func emailChanged(_ email: String?)
/// String value of password textfield text
func passwordChanged(_ password: String?)
/// Call when login button is pressed.
func loginButtonTapped()
}
public protocol LoginViewModelOutputs {
/// Emits on login.
var loginSuccess: Signal<(Bool), NoError> { get }
}
public protocol LoginViewModelType {
var inputs: LoginViewModelInputs { get }
var outputs: LoginViewModelOutputs { get }
}
public final class LoginViewModel: LoginViewModelType, LoginViewModelInputs, LoginViewModelOutputs {
public init() {
let emailAndPassword = Signal.combineLatest(
self.emailChangedProperty.signal.skipNil(),
self.passwordChangedProperty.signal.skipNil()
)
let tryLogin = loginButtonTappedProperty.map {
emailAndPassword.map(isValid)
}
self.loginSuccess = tryLogin.value
}
fileprivate let emailChangedProperty = MutableProperty<String?>(nil)
public func emailChanged(_ email: String?) {
self.emailChangedProperty.value = email
}
fileprivate let loginButtonTappedProperty = MutableProperty()
public func loginButtonTapped() {
self.loginButtonTappedProperty.value = ()
}
fileprivate let passwordChangedProperty = MutableProperty<String?>(nil)
public func passwordChanged(_ password: String?) {
self.passwordChangedProperty.value = password
}
public let loginSuccess: Signal<(Bool), NoError>
public var inputs: LoginViewModelInputs { return self }
public var outputs: LoginViewModelOutputs { return self }
}
func isValid(email: String, password: String) -> Bool {
return !email.characters.isEmpty && !password.characters.isEmpty
}
感谢任何帮助。我没有找到太多好的文档来了解信号或观察者,但我可能没找对地方。
Here 是使用 RAC 构建的输入表单的示例。
它有点过时了——本例中以 rex_
开头的所有内容(它是 UI 绑定的外部扩展库,现在直接集成到 RAC 中)现在更改为.reactive.
UITextField.rex_textSignal
现在是 UITextField.reactive.continuousTextValues
UIButton.rex_pressed
现在是 UIButton.reactive.pressed
您无需将凭据保存到 authenticationAction
中的 NSUserDefaults
,而是执行实际的身份验证操作。
顺便说一句: 你不应该将用户凭证,尤其是密码保存到 NSUserDefaults
。请改用钥匙串!
关键点是
- 在您的 viewModel 中使用
MutableProperty
来存储当前输入值
- 在界面元素上使用
.reactive
属性 和绑定运算符 <~
将您的 viewModel 绑定到输入 (viewModel.attribute <~ textField.reactive.continuouseTextValues
)
- 使用
Action
按需执行实际工作
- 通过
CocoaAction
(button.reactive.pressed = CocoaAction(viewModel.loginAction)
) 将 Action
绑定到 UI 控件
希望对你有帮助!
这是我会采用的方法
- 根据用户名和密码输入的验证启用和禁用登录按钮
- 将登录动作绑定到按钮事件
代码如下:
let usernameField: UITextField
let passwordField: UITextField
let loginEnabled: MutableProperty<Bool>
let loginButton: UIButton
loginEnabled <~
Signal.combineLatest(
usernameField.reactive.controlEvents(.allEditingEvents),
passwordField.reactive.controlEvents(.allEditingEvents))
.map { _ -> Bool in
return validation()
}
// only allow button to be pressed when validation succeeds
loginButton.reactive.isEnabled <~ loginEnabled
// login action
let loginAction = Action<(String?,String?),Void,NoError> { (username, password) -> SignalProducer<Void, NoError> in
// replace with login procedure
return SignalProducer.empty
}
// bind button event to login action
loginButton.reactive.pressed = CocoaAction(loginAction, input:
(usernameField.text, passwordField.text))
我第一次设置登录视图和使用响应式编程时 - 我无法从我的 ViewContoller 生成一个信号,该信号将在我的视图中使用包含我的表单验证的 Bool 提醒我的 observeValues
侦听器:
查看文件
viewModel.outputs.loginSuccess
.observeValues { [weak self] value in
print(value)
}
使用我当前的代码 loginSuccess
每次更改电子邮件或密码文本字段时都会触发(我的视图文件中有 .addTarget
用于更新我的模型视图文件中的 MutableProperites) .我遇到麻烦的地方是为 tryLogin
创建一个信号,该信号仅在按下登录按钮时发出,然后映射我的表单验证( emailAndPassword.map(isValid)
),我可以在我的视图文件中对其进行响应。
模型视图文件
import ReactiveCocoa
import ReactiveSwift
import Result
public protocol LoginViewModelInputs {
/// String value of email textfield text
func emailChanged(_ email: String?)
/// String value of password textfield text
func passwordChanged(_ password: String?)
/// Call when login button is pressed.
func loginButtonTapped()
}
public protocol LoginViewModelOutputs {
/// Emits on login.
var loginSuccess: Signal<(Bool), NoError> { get }
}
public protocol LoginViewModelType {
var inputs: LoginViewModelInputs { get }
var outputs: LoginViewModelOutputs { get }
}
public final class LoginViewModel: LoginViewModelType, LoginViewModelInputs, LoginViewModelOutputs {
public init() {
let emailAndPassword = Signal.combineLatest(
self.emailChangedProperty.signal.skipNil(),
self.passwordChangedProperty.signal.skipNil()
)
let tryLogin = loginButtonTappedProperty.map {
emailAndPassword.map(isValid)
}
self.loginSuccess = tryLogin.value
}
fileprivate let emailChangedProperty = MutableProperty<String?>(nil)
public func emailChanged(_ email: String?) {
self.emailChangedProperty.value = email
}
fileprivate let loginButtonTappedProperty = MutableProperty()
public func loginButtonTapped() {
self.loginButtonTappedProperty.value = ()
}
fileprivate let passwordChangedProperty = MutableProperty<String?>(nil)
public func passwordChanged(_ password: String?) {
self.passwordChangedProperty.value = password
}
public let loginSuccess: Signal<(Bool), NoError>
public var inputs: LoginViewModelInputs { return self }
public var outputs: LoginViewModelOutputs { return self }
}
func isValid(email: String, password: String) -> Bool {
return !email.characters.isEmpty && !password.characters.isEmpty
}
感谢任何帮助。我没有找到太多好的文档来了解信号或观察者,但我可能没找对地方。
Here 是使用 RAC 构建的输入表单的示例。
它有点过时了——本例中以 rex_
开头的所有内容(它是 UI 绑定的外部扩展库,现在直接集成到 RAC 中)现在更改为.reactive.
UITextField.rex_textSignal
现在是UITextField.reactive.continuousTextValues
UIButton.rex_pressed
现在是UIButton.reactive.pressed
您无需将凭据保存到 authenticationAction
中的 NSUserDefaults
,而是执行实际的身份验证操作。
顺便说一句: 你不应该将用户凭证,尤其是密码保存到 NSUserDefaults
。请改用钥匙串!
关键点是
- 在您的 viewModel 中使用
MutableProperty
来存储当前输入值 - 在界面元素上使用
.reactive
属性 和绑定运算符<~
将您的 viewModel 绑定到输入 (viewModel.attribute <~ textField.reactive.continuouseTextValues
) - 使用
Action
按需执行实际工作 - 通过
CocoaAction
(button.reactive.pressed = CocoaAction(viewModel.loginAction)
) 将
Action
绑定到 UI 控件
希望对你有帮助!
这是我会采用的方法
- 根据用户名和密码输入的验证启用和禁用登录按钮
- 将登录动作绑定到按钮事件
代码如下:
let usernameField: UITextField
let passwordField: UITextField
let loginEnabled: MutableProperty<Bool>
let loginButton: UIButton
loginEnabled <~
Signal.combineLatest(
usernameField.reactive.controlEvents(.allEditingEvents),
passwordField.reactive.controlEvents(.allEditingEvents))
.map { _ -> Bool in
return validation()
}
// only allow button to be pressed when validation succeeds
loginButton.reactive.isEnabled <~ loginEnabled
// login action
let loginAction = Action<(String?,String?),Void,NoError> { (username, password) -> SignalProducer<Void, NoError> in
// replace with login procedure
return SignalProducer.empty
}
// bind button event to login action
loginButton.reactive.pressed = CocoaAction(loginAction, input:
(usernameField.text, passwordField.text))