/
LocationPublisher.swift
91 lines (69 loc) 路 2.48 KB
/
LocationPublisher.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import Combine
import CoreLocation
protocol PublisherLocationDelegate: class {
func startLocationUpdates()
}
protocol SubscriptionLocationDelegate: class {
func didUpdate(with locations: [CLLocation])
func didFail(with error: Error)
}
final class LocationSubscription <S: Subscriber>:
NSObject,
SubscriptionLocationDelegate,
Subscription where S.Input == [CLLocation],
S.Failure == Error {
var subscriber: S?
private var publisherDelegate: PublisherLocationDelegate?
init(subscriber: S?, delegate: PublisherLocationDelegate?) {
self.subscriber = subscriber
self.publisherDelegate = delegate
}
func didUpdate(with locations: [CLLocation]) {
_ = subscriber?.receive(locations)
}
func didFail(with error: Error) {
_ = subscriber?.receive(completion: .failure(error))
}
func request(_ demand: Subscribers.Demand) {
publisherDelegate?.startLocationUpdates()
}
func cancel() {
subscriber = nil
publisherDelegate = nil
}
}
final class LocationPublisher: NSObject,
Publisher,
CLLocationManagerDelegate,
PublisherLocationDelegate {
typealias Output = [CLLocation]
typealias Failure = Error
private let manager: CLLocationManager
private var subscriberDelegate: SubscriptionLocationDelegate?
init(manager: CLLocationManager) {
self.manager = manager
super.init()
self.manager.delegate = self
}
// MARK: Publisher
func receive<S>(subscriber: S) where S : Subscriber, LocationPublisher.Failure == S.Failure, LocationPublisher.Output == S.Input {
let subscibtion = LocationSubscription(
subscriber: subscriber,
delegate: self
)
subscriber.receive(subscription: subscibtion)
subscriberDelegate = subscibtion
}
// MARK: CLLocationManagerDelegate
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
subscriberDelegate?.didFail(with: error)
manager.stopUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
subscriberDelegate?.didUpdate(with: locations)
}
// MARK: PublisherLocationDelegate
func startLocationUpdates() {
manager.startUpdatingLocation()
}
}