【问题标题】:How to make basic bindings in ReactiveCocoa 3 and 4如何在 ReactiveCocoa 3 和 4 中进行基本绑定
【发布时间】:2015-07-26 05:47:42
【问题描述】:

我最近一直在阅读 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)
    }
}

视图模型(MenuViewModel)

视图模型公开了不同的String 变量,让视图控制器显示菜单。让我们添加一个属性来显示主菜。

var mainCourse = MutableProperty("")

我们为这个属性添加一个绑定:

self.mainCourse <~ Menu.fetchTodaysMenu()
    |> map { menu in
        return menu.mainCourse!
    }

视图控制器(MenuViewController)

最后但并非最不重要的一点是,我想在一个视图中展示这门主菜。我会为此添加一个UILabel

var headline = UILabel()

最后我想通过观察我的视图模型来设置那个 UILabel 的text 属性。 喜欢的东西:

self.headline.text <~ viewModel.headline.producer

不幸的是,这不起作用。

问题

  1. fetchTodaysMenu() 方法返回一个SignalProducer&lt;Menu, NoError&gt;,但是如果我希望这个方法返回一个SignalProducer&lt;Menu, NSError&gt; 而不是呢?这将使我在视图模型中的绑定失败,因为该方法现在可能会返回错误。我该如何处理?
  2. 如前所述,我的视图控制器中的当前绑定不起作用。我一直在尝试创建一个代表UILabeltext 属性的MutableProperty,但我从来没有做对。我还认为必须为我要绑定的每个属性创建额外的变量感觉很笨拙或冗长。这在 RAC2 中是不需要的。我也有意避免使用DynamicProperty,但也许我不应该?我基本上只是想找到正确的做法RAC(self.headline, text) = RACObserve(self.viewModel, mainCourse);

非常感谢有关如何进行此基本设置的任何其他反馈/指导。

【问题讨论】:

标签: swift reactive-cocoa reactive-cocoa-3


【解决方案1】:

因此,在写完这个问题后,Colin Eberhardt 撰写了他的 RAC3 博客文章系列的第 3 部分,其中包括一个使用 MVVM 和 RAC3 的有趣且非常相关的示例。帖子可以找到here和源代码here

根据他的工作,我已经设法回答了我自己的问题:

  1. 通过采用稍微不同的方法,我可以让fetchTodaysMenu() 根据需要返回SignalProducer&lt;Menu, NSError&gt;。以下是我在视图模型中的操作方式:

    MenuService.fetchTodaysMenu()
        |> observeOn(QueueScheduler.mainQueueScheduler)
        |> start(next: { response in
            self.mainCourse.put(response.mainCourse!)
        }, error: {
            println("Error \($0)")
        })
    
  2. 似乎在 RAC3 beta 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() |&gt; ignoreError 进行绑定。

我开源了我的项目,因为这对于其他研究 ReactiveCocoa 3.0 的人来说可能是一个很好的起点: https://github.com/s0mmer/TodaysReactiveMenu

2016 年 3 月 5 日更新

正如 cmets 中强调的那样,从 Swift 2 开始,ignoreError 函数现在看起来像:

public func ignoreError() -> SignalProducer<Value, NoError> {
    return flatMapError { _ in
        SignalProducer<Value, NoError>.empty
    }
}

此外,还制作了一个名为 Rex 的扩展库,其中添加了类似的内容。

【讨论】:

  • 使用 Swift 2,您需要使用 flatMapError 而不是 catch 以避免与 Swift 2 的 catch 冲突。
猜你喜欢
  • 2015-12-23
  • 1970-01-01
  • 1970-01-01
  • 2016-01-15
  • 2017-10-28
  • 1970-01-01
  • 2016-02-12
  • 2015-07-19
  • 1970-01-01
相关资源
最近更新 更多