Swift Combine - 为 CoreLocation 创建发布者

Dam*_*ycz 4 publisher core-location reactive-programming swift combine

我才开始学习结合,所以对我来说还是有点模糊。我想创建一个 custom PublisherCLLocationManager用于公开当前用户位置。我希望它以这样的方式工作,locationManager只有在有一些订阅者连接时才开始更新位置。在所有订阅者被删除、取消等之后,它应该停止更新位置。这是可能的吗?我怎样才能创建这样的publisher?这也是正确的方法,还是有什么问题?

hec*_*ckj 6

你想要的东西的基础非常简单。有一个来自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))
    }
}
Run Code Online (Sandbox Code Playgroud)

这并不能完全满足您的要求,因为它不会在订阅时自动开始更新,但我怀疑您可以扩展它以启用该功能。

到目前为止,我还没有深入研究通过实现协议所需的所有方法来制作我自己的发布者,所以我没有扩展到该机制的细节。尽管大多数发布者和运营商在创建发布者或订阅时触发,但当您希望显式控制更新时,Combine 本身具有ConnectablePublisher的概念。

一般来说,如果你应该这样做,你的用例会更好地回答。在某些情况下,您在更新视图之前创建管道和订阅 - 如果是这种情况,那么推迟请求后台更新会为您节省一些处理能力和能源消耗。

在使用此 CoreLocation 发布器的 UIKit 示例中,我还提供了验证已请求权限以允许位置更新的机制,嵌入在示例视图控制器中:https : //github.com/heckj/swiftui-notes/ blob/master/UIKit-Combine/HeadingViewController.swift