/
APIFetcher.swift
executable file
·58 lines (48 loc) · 1.81 KB
/
APIFetcher.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
import Alamofire
import ReactiveSwift
public class APIFetcher: Fetcher {
private let url: String
private let keyPath: String
private lazy var _version: Property<Int?> = Property(initial: nil, then: self._fetch.values)
private lazy var _fetch: Action<Void, Int?, NSError> = Action { [unowned self] in
let producer = SignalProducer<Any, NSError> { [unowned self] sink, _ in
Alamofire.request(self.url).response {
let request = $0.request
let response = $0.response
let data = $0.data
let error = $0.error
switch (data, error) {
case (_, .some(let e)):
sink.send(error: e as NSError)
case (.some(let d), _):
do {
let json = try JSONSerialization.jsonObject(with: d, options: .allowFragments)
sink.send(value: json)
sink.sendCompleted()
} catch {
sink.send(error: error as NSError)
return
}
default: break
}
}
}
return producer.map {
guard let value = ($0 as AnyObject).value(forKeyPath: self.keyPath) else { return nil }
if let stringValue = value as? String {
return Int(stringValue)
}
return value as? Int
}
}
public var version: Int? { return _version.value }
// MARK: - Initialization
public init(url: String, keyPath: String) {
self.url = url
self.keyPath = keyPath
}
// MARK: - Public interface
public func fetch(completion: @escaping () -> Void) {
_fetch.apply().startWithCompleted { completion() }
}
}