我才刚刚开始学习结合,所以对我来说还是有点模糊。我想创建一个自定义Publisher
,它将使用CLLocationManager
公开当前用户位置。我希望它以这种方式工作,即locationManager
仅在连接了一些订户时才开始更新位置。并且在所有订户被删除,取消等之后,它应该停止更新位置。这可能吗?如何创建这样的publisher
?这也是正确的方法,还是存在问题?
最佳答案
所需内容的基础非常简单。有一个来自Using Combine的示例,该示例将CoreLocation与充当代理的对象包装在一起,返回了CLHeading
更新的发布者。
CoreLocation本身不会自动启动或停止这种事情,在代理对象中,我复制了该模式,以允许您手动启动和停止更新过程。
代码的核心在https://github.com/heckj/swiftui-notes/blob/master/UIKit-Combine/LocationHeadingProxy.swift中
import Foundation
import Combine
import CoreLocation
final class LocationHeadingProxy: NSObject, CLLocationManagerDelegate {
let mgr: CLLocationManager
private let headingPublisher: PassthroughSubject<CLHeading, Error>
var publisher: AnyPublisher<CLHeading, Error>
override init() {
mgr = CLLocationManager()
headingPublisher = PassthroughSubject<CLHeading, Error>()
publisher = headingPublisher.eraseToAnyPublisher()
super.init()
mgr.delegate = self
}
func enable() {
mgr.startUpdatingHeading()
}
func disable() {
mgr.stopUpdatingHeading()
}
// MARK - delegate methods
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
headingPublisher.send(newHeading)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
headingPublisher.send(completion: Subscribers.Completion.failure(error))
}
}
这并不能完全满足您的要求,因为它不会在订阅后自动启动更新,但是我怀疑您可以扩展此功能以启用该功能。
到目前为止,我还没有通过实现协议所需的所有方法来研究自己的发布者,因此我没有扩展到该机制的细节。当您希望对更新进行明确控制时,尽管大多数发布者和操作员都会在创建发布者或订阅时触发,但是Combine本身具有ConnectablePublisher的概念。
通常,如果您应该这样做,则可以通过用例更好地解决。在某些情况下,您需要先创建管道并进行订阅,然后再更新视图-如果是这种情况,那么推迟请求后台更新将为您节省一些处理能力和能源消耗。
在使用此CoreLocation发布者的UIKit示例中,我还具有适当的机制来验证是否已请求权限请求,以允许位置更新,并嵌入在示例视图控制器中:https://github.com/heckj/swiftui-notes/blob/master/UIKit-Combine/HeadingViewController.swift