Ios 在Combine中处理发布服务器错误的最佳做法是什么?(从CoreLocation发布标题更新)
我一直在开发一个应用程序,其中有一个指南针,可以根据发布标题更改和创建出版商来处理这些更改来更新标题 我对反应式编程非常陌生,但我遇到的问题似乎是一个常见的问题,所以我想发布它,看看是否有人能提供帮助 有时它会工作一段时间,发布者会发布新的标题并更新UI,但随后就会停止工作。其他时候,它永远不会开始更新(在任何标题更新之前传递错误)。在任何一种情况下,事件都会停止,因为故障完成事件正在发送到发布服务器:Ios 在Combine中处理发布服务器错误的最佳做法是什么?(从CoreLocation发布标题更新),ios,swift,core-location,combine,Ios,Swift,Core Location,Combine,我一直在开发一个应用程序,其中有一个指南针,可以根据发布标题更改和创建出版商来处理这些更改来更新标题 我对反应式编程非常陌生,但我遇到的问题似乎是一个常见的问题,所以我想发布它,看看是否有人能提供帮助 有时它会工作一段时间,发布者会发布新的标题并更新UI,但随后就会停止工作。其他时候,它永远不会开始更新(在任何标题更新之前传递错误)。在任何一种情况下,事件都会停止,因为故障完成事件正在发送到发布服务器: func locationManager(_ manager: CLLocationMana
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)
我意识到我无法将错误发送给发布者(这是我应该做的吗?为标题更新指定一个特定的发布者,该发布者从不发送错误?),而在订阅端处理它可能是一种最佳做法,或者有一些在错误后恢复的最佳做法。正如您所指出的,当发生错误时,这将始终结束由现成操作员构建的联合管道。这是一个特性,不是bug。特别令人惊讶的是,即使使用了错误处理操作符,如
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
让myNumberPublisher=PassthroughSubject()
//外部管道永远不会出错(错误类型为never):
myNumberPublisher
.map(String.init)//转换为字符串
.flatMap{中的数字
//内部管道可能会出错:
URLSession.shared.dataTaskPublisher(用于:URL(字符串):https://square?n=\(数字)“)!)
.replaceError(带有“Oopsies”)
.map{“答案是\(答案)”中的答案}
}
.sink{打印结果(结果)}
myNumberPublisher.send(“5”)
//=>答案是25
myNumberPublisher.send(“3”)//此处假设端点错误
//=>答案是糟糕
myNumberPublisher.send(“6”)
//=>答案是36
要在您的案例中使用
flatMap
,向发布者提供服务的类可能会要求您在出现错误时请求新的发布者
或者,您可以修改headingPublisher
,使其具有Never
错误类型。如果按此方法操作,错误应由出售headingPublisher
的对象处理
另一种选择是向两个发布者出售,一个用于价值,另一个用于错误:
AnyPublisher
AnyPublisher
这些选项中的任何一个都可以使用,您选择的选项将取决于您的需要。以下内容可能对*使用联合收割机有所帮助“这本书。这确实有助于我走上正确的道路,但我认为我现在需要学习更多,并尝试找到一些例子。我真的不知道你所说的内部和外部管道是什么意思,或者在这种情况下如何使用
flatMap
,而没有看到一个示例。此外,我不确定您所说的“修改您的标题发布者
以获得从不
错误类型”是什么意思,因此我将进一步研究这些问题,它们会有帮助,我一定会回来接受答案。谢谢这是一个很难的话题,也很难简明扼要地解释。我添加了一个简单的例子来帮助解释。如果您查看Combine内置发布服务器的文档,您会注意到其中一些被描述为“永不失败”。例如,Just
publisher。当您通过调用.eraseToAnyPublisher()
键入擦除一个未失败的发布服务器时,您将看到该发布服务器的类型将是AnyPublisher
“尤其令人惊讶的是,即使您使用了错误处理操作符(如catch或replaceError),管道也会终止。”