假设我有一个应用程序显示当天的菜单.该应用程序正在使用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) } }
视图模型暴露了不同的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>代替?这将使我的视图模型中的绑定失败,因为该方法现在可能会返回一个错误.我该如何处理?
>如上所述,我的视图控制器中的当前绑定不起作用.我一直在玩,创建一个代表UILabel的文本属性的MutableProperty,但是我从来没有这样做.我也觉得笨拙或冗长地为每个要绑定的属性创建额外的变量.这在RAC2中不是必需的.我有意试图避免使用DynamicProperty,但也许我不应该我基本上只是想找到正确的方式做RAC(self.headline,text)= RACObserve(self.viewmodel,mainCourse);.
任何其他反馈/指导如何使这个基本设置受到高度赞赏.
根据他的工作,我设法回答了我自己的问题:
>通过略微不同的方法,我可以使fetchTodaysMenu()返回一个SignalProducer< Menu,NSError>按需要以下是我在视图模型中做的事情:
MenuService.fetchTodaysMenu() |> observeOn(QueueScheduler.mainQueueScheduler) |> start(next: { response in self.mainCourse.put(response.mainCourse!) },error: { println("Error \($0)") })
>似乎没有UIKit绑定,而是RAC3 beta 4. 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 } }