ios - 在 Combine 中处理发布者错误的最佳实践是什么? (从 CoreLocation 发布航向更新)

标签 ios swift core-location combine

我一直在开发一个带有指南针的应用程序,它根据 this example 更新其标题。用于发布标题更改和 this example用于创建发布者来处理这些更改。

我是响应式编程的新手,但我遇到的问题似乎是一个常见问题,所以我想发布它,看看是否有人可以提供帮助。

有时它会工作一段时间,发布者会发布新标题并更新用户界面,但随后就会停止工作。其他时候,它永远不会开始更新(在任何标题更新之前都会传递错误)。无论哪种情况,事件都会停止,因为失败完成事件被发送到发布者:

func locationManager(_ manager: CLLocationManager,
                     didFailWithError error: Error) {

    headingPublisher.send(completion: Subscribers.Completion.failure(error))

    print("error: \(error.localizedDescription)")
}

首先,我试图弄清楚这些错误是什么,以便我可以尝试更好地处理它们……这些错误真的值得让发布商停止吗?我想知道标题更新的中途会发生什么样的错误,因为标题更新在错误后恢复,即使发布者停止。我尝试打印错误,但我得到的只是这个,这似乎没有帮助: 错误:操作无法完成。 (kCLErrorDomain 错误 0。)

我不擅长 iOS,所以如果有人对如何在此处获得更好的错误描述有任何建议,请告诉我。

其次,我想知道如何忽略订阅发布者的错误,如果这是我应该做的,那么即使出现错误,.sink 也会继续获取航向更新.下面是我的发布商代码,基于示例:

    _ = headingProxy
        .publisher
        .receive(on: RunLoop.main)
        .sink(receiveCompletion: { completion in },
              receiveValue: { [weak self] (heading) in
                self?.currentHeadingAccuracy = heading.headingAccuracy
                self?.currentHeading = heading.trueHeading
        })
        .store(in: &cancellableSet)

我意识到我永远无法将错误发送给发布者(这是我应该做的吗?有一个特定的发布者只用于从不发送错误的标题更新?)但我假设做这件事的人包括发送有充分理由向发布者报告错误,最好的做法是在订阅端处理错误,或者有一些最佳做法可以在错误后恢复。

最佳答案

正如您所指出的,当发生错误时,将始终终止使用现成运算符构建的 Combine 管道。这是一个功能,而不是错误。特别令人惊讶的是,即使您使用像 catch 这样的错误处理运算符,管道也会结束。或 replaceError .

您可以通过包装可能在 flatMap 中发生错误的管道的任何部分来使管道对错误具有弹性.

将您的主管道视为“外部”管道,并将管道包裹在 flatMap 中作为“内部”管道。确保外部管道的错误类型是 Never它可以永远继续处理值。

考虑一个返回数字平方的端点:

let myNumberPublisher = PassthroughSubject<Int, Never>()

// Outer pipeline will never error (the Error type is Never):
myNumberPublisher
  .map(String.init) // convert to string
  .flatMap { number in
    // Inner pipeline can error:
    URLSession.shared.dataTaskPublisher(for: URL(string: "https://square?n=\(number)")!)
      .replaceError(with: "Oopsies")
      .map { answer in "The answer is \(answer)" }
  }
  .sink { result in print(result) }

myNumberPublisher.send("5")
// => The answer is 25
myNumberPublisher.send("3") // assume the endpoint errors here
// => The answer is Oopsies
myNumberPublisher.send("6")
// => The answer is 36


使用flatMap在您的情况下,出售发布者的类可能会要求您在发生错误时随时请求新的发布者。

或者,您可以修改您的 headingPublisher有一个Never错误类型。如果你走这条路,错误应该由提供 headingPublisher 的对象处理。 .

另一种选择是出售两个发布者,一个用于值,另一个用于错误:

  • AnyPublisher<ValueType, Never>
  • AnyPublisher<Error, Never>

这些选项中的任何一个都可以使用,您选择的选项将取决于您的需求。

关于ios - 在 Combine 中处理发布者错误的最佳实践是什么? (从 CoreLocation 发布航向更新),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59148845/

相关文章:

ios - 如何从 Firebase 获取单个数据库引用

IOS-didFailWithError : Error Domain=kCLErrorDomain Code=0.(kCLErrorDomain 错误 0。)”

ios - Goertzel算法给出无限结果

ios - 切换保存用户首选项

objective-c - CoreLocation kCLErrorDomain 错误 5

arrays - 搜索整个数组 Swift

ios - 在swift4中查找按钮的文本颜色

ios - 为什么我的本地通知没有在 iOS 10 的前台触发?

iphone - UIButton 标记未在 cellForRowAtIndexPath 中正确设置

ios - UIScrollView 在键盘关闭时停止滚动