我试图理解 ReactiveCocoa 4 的一些概念,但没有找到一种方法来根据登录表单的输入正确验证和发送请求。
我当前的解决方案会在输入的每次有效更新时发送请求,这并不好。
看来我需要使用 Actions 和 CocoaActions 来解决我的问题,但我不明白如何正确实现它们。
这是我的代码示例:
我希望在按下登录按钮并且登录和密码字段都不为空时发送登录请求,否则我只会显示错误。
目前,当我修改输入字段时,生产者仍然活着并继续发送请求,这不太好......
我想要一个关于如何正确执行它的例子:)
登录 View 模型.swift
class LoginViewModel {
let login = MutableProperty<String>("")
let password = MutableProperty<String>("")
init() {
}
func logIn() -> SignalProducer<Int, IntranetError> {
return SignalProducer {
observer, disposable in
combineLatest(self.login.producer, self.password.producer)
.promoteErrors(Moya.Error)
.filter { (credentials : (String, String)) in
guard credentials.0.length > 0 else {
observer.sendFailed(IntranetError.MissingLoginError)
return false
}
guard credentials.1.length > 0 else {
observer.sendFailed(IntranetError.MissingPasswordError)
return false
}
return true
}
.flatMap(.Latest) { (credentials : (String, String)) -> SignalProducer<User, Moya.Error> in
let login = credentials.0
let password = credentials.1
return IntranetProvider.request(Intranet.LogIn(login, password)).filterSuccessfulStatusCodes()
.mapObject(User)
}
.start { (event) -> Void in
switch event {
case .Next(let user):
UserManager.sharedManager.user = user;
print(user)
observer.sendCompleted()
case .Failed(let error):
observer.sendFailed(.MoyaError(error))
default:
break
}
}
}
}
}
LoginViewController.swift
class LoginViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var loginTextField: FramedTextField!
@IBOutlet weak var passwordTextField: FramedTextField!
@IBOutlet weak var connectButton: UIButton!
let viewModel : LoginViewModel = LoginViewModel()
override func viewDidLoad() {
super.viewDidLoad()
viewModel.login <~ loginTextField.rac_text
viewModel.password <~ passwordTextField.rac_text
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func connectButtonTouched(sender: AnyObject) {
loginAsked()
}
func loginAsked() -> Void {
SVProgressHUD.showWithMaskType(.Black)
viewModel.logIn().throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler).start { (event) in
switch event {
case .Completed:
SVProgressHUD.dismiss()
self.connectionSuccessfull()
case .Failed(let error):
switch error {
case .MissingPasswordError :
SVProgressHUD.showErrorWithStatus(NSLocalizedString("Missing password", comment: "User password is missing"))
case .MissingLoginError :
SVProgressHUD.showErrorWithStatus(NSLocalizedString("Missing login", comment: "User login is missing"))
case .MoyaError(let error) :
SVProgressHUD.showErrorWithStatus(error.toString())
default :
SVProgressHUD.showErrorWithStatus(NSLocalizedString("Internal error, please try again later", comment: ""))
}
default:
break
}
}
}
}
谢谢
最佳答案
经过漫长的一夜努力,我终于找到了正确实现它的方法。
最后我想多了一点验证过程,现在简单多了。
结果:
LoginViewModel.swift
class LoginViewModel {
let login = MutableProperty<String>("")
let password = MutableProperty<String>("")
var loginAction : Action<(String, String), User, IntranetError>!
var cocoaActionLogin : CocoaAction!
init() {
loginAction = Action { (let login, let password) in
return SignalProducer {
observer, disposable in
guard login.length > 0 else {
observer.sendFailed(IntranetError.MissingLoginError)
return
}
guard password.length > 0 else {
observer.sendFailed(IntranetError.MissingPasswordError)
return
}
print("SENT")
IntranetProvider.request(Intranet.LogIn(login, password))
.filterSuccessfulStatusCodes()
.mapObject(User)
.start { (event) in
switch event {
case .Next(let user):
UserManager.sharedManager.user = user;
print(user)
observer.sendCompleted()
case .Failed(let error):
observer.sendFailed(.MoyaError(error))
default:
observer.sendCompleted()
}
}
}
}
cocoaActionLogin = CocoaAction(loginAction) { _ in
return (self.login.value, self.password.value)
}
}
}
LoginViewController.swift
class LoginViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var loginTextField: FramedTextField!
@IBOutlet weak var passwordTextField: FramedTextField!
@IBOutlet weak var connectButton: UIButton!
let viewModel : LoginViewModel = LoginViewModel()
override func viewDidLoad() {
super.viewDidLoad()
viewModel.login <~ loginTextField.rac_text
viewModel.password <~ passwordTextField.rac_text
connectButton.addTarget(self.viewModel.cocoaActionLogin, action: CocoaAction.selector, forControlEvents: .TouchUpInside)
self.viewModel.loginAction.events
.observeOn(UIScheduler())
.observeNext { (event) in
switch event {
case .Completed:
SVProgressHUD.dismiss()
self.connectionSuccessfull()
case .Failed(let error):
switch error {
case .MissingPasswordError :
SVProgressHUD.showErrorWithStatus(NSLocalizedString("Missing password", comment: "User password is missing"))
case .MissingLoginError :
SVProgressHUD.showErrorWithStatus(NSLocalizedString("Missing login", comment: "User login is missing"))
case .MoyaError(let error) :
SVProgressHUD.showErrorWithStatus(error.toString())
default :
SVProgressHUD.showErrorWithStatus(NSLocalizedString("Internal error, please try again later", comment: ""))
}
default:
break
}
}
}
}
关于ios - ReactiveCocoa 4,根据 UI 事件和验证正确发送我的 HTTP 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34713724/
我正在使用i18n从头开始构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在rubyonrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送
我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道rubyonrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim
是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s
我的工作要求我为某些测试自动生成电子邮件。我一直在四处寻找,但未能找到可以快速实现的合理解决方案。它需要在outlook而不是其他邮件服务器中,因为我们有一些奇怪的身份验证规则,我们需要保存草稿而不是仅仅发送邮件的选项。显然win32ole可以做到这一点,但我找不到任何相当简单的例子。 最佳答案 假设存储了Outlook凭据并且您设置为自动登录到Outlook,WIN32OLE可以很好地完成此操作:require'win32ole'outlook=WIN32OLE.new('Outlook.Application')message=