我最近一直在阅读ReactiveCocoa v3,而且我只是在设置基本内容时苦苦挣扎。我已经阅读了变更日志,测试,少数SO问题和Colin Eberhardt关于这个主题的文章。但是,我仍然缺少基本绑定的示例。
我们说我有一个提供当天菜单的应用程序。该应用程序正在使用RAC3和MVVM模式。
型号(菜单)
该模型有一个简单的方法来获取今天的菜单。至于现在,这不做任何网络请求,它基本上只是创建一个模型对象。 mainCourse
属性为String
。
class func fetchTodaysMenu() -> SignalProducer<Menu, NoError> {
return SignalProducer {
sink, dispoable in
let newMenu = Menu()
newMenu.mainCourse = "Some meat"
sendNext(sink, newMenu)
sendCompleted(sink)
}
}
ViewModel(MenuViewModel)
视图模型公开了不同的String
变量,以便让视图控制器显示菜单。让我们只添加一个属性来显示主菜。
var mainCourse = MutableProperty("")
我们为此属性添加了一个绑定:
self.mainCourse <~ Menu.fetchTodaysMenu()
|> map { menu in
return menu.mainCourse!
}
ViewController(MenuViewController)
最后但并非最不重要的是,我想在视图中介绍这个主要课程。我将为此添加UILabel
。
var headline = UILabel()
最后我想通过观察我的视图模型来设置该UILabel的text
属性。 之类的东西:
self.headline.text <~ viewModel.headline.producer
遗憾的是,这不起作用。
问题
fetchTodaysMenu()
会返回SignalProducer<Menu, NoError>
,但如果我希望此方法返回SignalProducer<Menu, NSError>
,该怎么办?这将使我的视图模型中的绑定失败,因为该方法现在可能会返回错误。我该如何处理?MutableProperty
的{{1}}属性的text
,但我从来没有做对。我还认为必须为我想要绑定的每个属性创建额外的变量,感觉笨拙或冗长。 RAC2不需要这样做。我故意也试图避免使用UILabel
,但也许我不应该这样做?我基本上只想找到正确的做法DynamicProperty
。我们非常感谢您提供有关如何进行此基本设置的任何其他反馈/指导。
答案 0 :(得分:13)
因此,在写完这个问题后,Colin Eberhardt撰写了他的RAC3博客文章系列的第3部分,其中包括一个使用MVVM和RAC3的有趣且非常相关的例子。可以找到帖子here和源代码here。
根据他的工作,我设法回答了我自己的问题:
采用稍微不同的方法,我可以让fetchTodaysMenu()
按需要返回SignalProducer<Menu, NSError>
。以下是我在视图模型中的操作方法:
MenuService.fetchTodaysMenu()
|> observeOn(QueueScheduler.mainQueueScheduler)
|> start(next: { response in
self.mainCourse.put(response.mainCourse!)
}, error: {
println("Error \($0)")
})
从RAC3测试版4开始,似乎还没有UIKit
绑定.Colin自己做了一些UIKit
扩展,以帮助他制作我正在寻找的这些绑定。这些可以找到here。将它们添加到我的项目中,使我能够完全按照自己的意愿行事:
self.mainCourse.rac_text <~ self.viewModel.mainCourse
2015年5月25日更新
在使用ReactiveCocoa 3工作了很多之后,我想再次回答1)。通过使用catch
,可以以更具说明性的方式执行此操作。我最终为此实现了一个小辅助函数:
public func ignoreError<T: Any, E: ErrorType>(signalProducer: SignalProducer<T, E>) -> SignalProducer<T, NoError> {
return signalProducer
|> catch { _ in
SignalProducer<T, NoError>.empty
}
}
该函数可将NSError
转换为NoError
,从而可以按照我想要的方式MenuService.fetchTodaysMenu() |> ignoreError
进行绑定。
我开源我的项目,因为这可能是其他人研究ReactiveCocoa 3.0的一个很好的起点: https://github.com/s0mmer/TodaysReactiveMenu
2016年3月5日更新
正如评论中所强调的,自Swift 2以来,ignoreError
函数现在看起来像:
public func ignoreError() -> SignalProducer<Value, NoError> {
return flatMapError { _ in
SignalProducer<Value, NoError>.empty
}
}
此外,还制作了一个名为Rex的扩展库,其中添加了类似的内容。