如何在 Swift Combine 中创建自定义链?
Posted
技术标签:
【中文标题】如何在 Swift Combine 中创建自定义链?【英文标题】:How to create a custom chain in Swift Combine? 【发布时间】:2020-09-30 02:24:23 【问题描述】:我正在尝试为 Combine 创建一个 LocationManager
包装器。我有一个发布者和一些触发发布者的功能。但是,我想将它们与自定义命令组合在一起。
这是我目前得到的:
@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)
要使用它,我必须先订阅,然后调用请求授权函数:
cancellable = locationProxy.authorizationPublisher
.sink status in
print(status)
locationProxy.requestAuthorization()
有没有办法在一次调用中构造代码以订阅和请求授权,如下所示:
cancellable = locationProxy.authorizationPublisher
.sink status in
print(status)
.requestAuthorization()
【问题讨论】:
【参考方案1】:您的requestAuthorization
应该返回发布者:
func requestAuthorization(for type: LocationAPI.AuthorizationType = .whenInUse) -> AnyPublisher<Bool, Never>
// start authorization flow
return authorizationPublisher
我还建议您使用CurrentValueSubject
而不是PassthroughSubject
,这样您在订阅authorizationPublisher
时始终可以获得“当前”状态。
【讨论】:
以上是关于如何在 Swift Combine 中创建自定义链?的主要内容,如果未能解决你的问题,请参考以下文章
如何在Xcode + Swift 4中创建自定义UIBarButtonItem类?
iOS - 如何在没有第三方框架的情况下在 Swift 中创建自定义动画横幅
在 Swift 中创建自定义(八角形)UIButton 的最佳方法