如何分割信号并在以后再次合并?

时间:2015-01-09 10:19:58

标签: reactive-cocoa frp

我不太确定如何正确地做到这一点,而且我可能错过了一些关于FRP的概念,因为我不久以来一直在玩ReactiveCocoa。

我的情况是这样的 - 我有信号:

  • 从本地商店加载对象;
  • 从远程商店加载对象;
  • 将远程对象保存到本地商店;
  • 将对象从本地商店转换(映射)为不同的格式

我希望有一个我可以订阅的信号,它将:

  • 通过localId从本地商店加载对象;
  • 在这里分割信号:
    • 将初始对象发送给信号的订户:
      • 将对象转换为其他格式;
      • 将此格式发送给最终订阅者;
    • 从远程存储更新本地对象并发送更新后的版本;
      • 使用刚加载的本地对象中的remoteId从远程存储加载对象;
      • 将该远程对象保存到本地存储;
      • 从原始localId;
      • 重新加载本地商店中的对象
      • 将对象转换为其他格式;
      • 将此格式发送给最终订阅者;
      • 完成信号。

所有这一切背后的想法是我的主要加载对象信号应返回对象的初始版本(如本地存储),同时从远程存储更新该对象,最后发送更新的版本。因此,最终订阅者应该在完成之前两次接收该对象。

远程加载信号取决于本地加载信号,因为我们必须加载本地对象才能获取对象的remoteId。因此,我想避免在启动信号时两次加载本地对象(一次用于发送到原始订户,一次用于获取remoteId以加载远程对象)。

我想出的初始解决方案是使本地负载信号成为多播(autoconnected)信号,然后将此信号(与链接到其上的变换)合并为相同的信号(使用远程负载,链接到它的保存,加载和转换)。但是,这永远不会进入远程负载,我只能认为是由于本地负载信号发送completed

有什么办法可以做我想做的事吗?我的逻辑错了吗? 提前感谢任何建议。

1 个答案:

答案 0 :(得分:0)

一种可能性是使用主题。如果您不熟悉,可以订阅主题,就像正常信号一样,但您可以明确地告诉它发送值(或错误或已完成的消息)。您还可以订阅“信号主题”,主题会将该信号的消息传播给自己的订阅者。

您可能希望以更漂亮的方式将其封装起来,但我认为以下内容可以满足您的需求:

let subject = RACSubject()

subject.map {
    let localObject = $0 as! LocalObjectType
    return transformLocalFormToFinalForm(localObject)
}
.subscribeNext { 
    let finalObject = $0 as! FinalObjectType
    // Process your final object here
}


let localObjectId = ... // Assuming the ID exists

getLocalObject(localObjectId).doNext { 
    subject.sendNext($0) 
}
.flattenMap {
    let localObject = $0 as! LocalObjectType
    return getRemoteObject(localObject.remoteId)
}
.flattenMap {
    let remoteObject = $0 as! RemoteObjectType
    return saveRemoteObjectToLocalStore(remoteObject)
}
.flattenMap {
    return getLocalObject(localObjectId)
}
.subscribeNext({
    subject.sendNext($0)
    subject.sendCompleted()
}, error {
    subject.sendError($0)
})

此设置应执行以下操作:

  1. 从ID中获取本地对象
  2. 将本地对象发送给主题(这会被转换并发送给最终订阅者)
  3. 使用本地对象中的远程ID获取远程对象
  4. 将远程对象保存到本地存储
  5. 从原始ID
  6. 获取(现在更新的)本地对象
  7. 将本地对象和已完成的消息发送给主题(如果链中的任何位置发生错误,则发生错误)
  8. 希望这有帮助!