本文介绍了如何在Swift Combine中创建自定义链?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为Combine创建一个 LocationManager 包装器.我有一个发布者和一些触发发布者的功能.但是,我想将它们与自定义命令结合在一起.

I'm trying to create a LocationManager wrapper for Combine. I have a publisher and some functions that trigger the publisher. However, I'd like to combine them in one with a custom command.

这是我到目前为止所得到的:

Here's what I got so far:

@available(OSX 10.15, iOS 13, tvOS 13, watchOS 6, *)
public class LocationProxy: NSObject {
    private lazy var manager = CLLocationManager()

    private static let authorizationSubject = PassthroughSubject<Bool, Never>()
    public private(set) lazy var authorizationPublisher: AnyPublisher<Bool, Never> = Self.authorizationSubject.eraseToAnyPublisher()

    var isAuthorized: Bool { CLLocationManager.isAuthorized }

    func isAuthorized(for type: LocationAPI.AuthorizationType) -> Bool {
        guard CLLocationManager.locationServicesEnabled() else { return false }

        #if os(macOS)
        return type == .always && CLLocationManager.authorizationStatus() == .authorizedAlways
        #else
        return (type == .whenInUse && CLLocationManager.authorizationStatus() == .authorizedWhenInUse)
            || (type == .always && CLLocationManager.authorizationStatus() == .authorizedAlways)
        #endif
    }

    func requestAuthorization(for type: LocationAPI.AuthorizationType = .whenInUse) {
        // Handle authorized and exit
        guard !isAuthorized(for: type) else {
            Self.authorizationSubject.send(true)
            return
        }

        // Request appropiate authorization before exit
        defer {
            #if os(macOS)
            if #available(OSX 10.15, *) {
                manager.requestAlwaysAuthorization()
            }
            #elseif os(tvOS)
            manager.requestWhenInUseAuthorization()
            #else
            switch type {
            case .whenInUse:
                manager.requestWhenInUseAuthorization()
            case .always:
                manager.requestAlwaysAuthorization()
            }
            #endif
        }

        // Handle mismatched allowed and exit
        guard !isAuthorized else {
            // Process callback in case authorization dialog not launched by OS
            // since user will be notified first time only and ignored subsequently
            Self.authorizationSubject.send(false)
            return
        }

        // Handle denied and exit
        guard CLLocationManager.authorizationStatus() == .notDetermined else {
            Self.authorizationSubject.send(false)
            return
        }
    }

    public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        guard status != .notDetermined else { return }
        Self.authorizationSubject.send(isAuthorized)
    }
}

要使用它,我必须先订阅,然后调用请求授权功能:

To use it, I have to subscribe first, then call the request authorization function:

cancellable = locationProxy.authorizationPublisher
    .sink { status in
        print(status)
    }

locationProxy.requestAuthorization()

有没有一种方法可以构造代码以在一个调用中订阅和请求授权,就像这样:

Is there a way to structure the code to subscribe and request authorization in one call, something like this:

cancellable = locationProxy.authorizationPublisher
    .sink { status in
        print(status)
    }
    .requestAuthorization()

推荐答案

您的 requestAuthorization 应该返回发布者:

func requestAuthorization(for type: LocationAPI.AuthorizationType = .whenInUse) -> AnyPublisher<Bool, Never> {
  // start authorization flow

  return authorizationPublisher
}

我还建议您使用 CurrentValueSubject 而不是 PassthroughSubject ,以便在订阅 authorizationPublisher 时始终可以获取当前"状态.代码>.

I would also recommend that you use a CurrentValueSubject instead of a PassthroughSubject so you can always get the "current" status when subscribing to the authorizationPublisher.

这篇关于如何在Swift Combine中创建自定义链?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-18 11:15
查看更多