Created
August 19, 2020 21:19
-
-
Save AquaGeek/0bdeec31263b4a871d5f02426719fe0a to your computer and use it in GitHub Desktop.
Example of how to use SignalProducer to fetch multiple pages
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private func fetchAllUsers() -> SignalProducer<[User], Error> { | |
let decoder = JSONDecoder() | |
decoder.keyDecodingStrategy = .convertFromSnakeCase | |
func fetchUsers(since lastSeenUserID: Int?) -> SignalProducer<[User], Error> { | |
var components = URLComponents(string: "https://api.github.com/users")! | |
if let userID = lastSeenUserID { | |
components.queryItems = [ | |
URLQueryItem(name: "since", value: userID.description) | |
] | |
} | |
var request = URLRequest(url: components.url!) | |
request.setValue("application/vnd.github.v3+json", forHTTPHeaderField: "Accept") | |
return URLSession.shared.reactive | |
.data(with: request) | |
.flatMap(.concat) { (data, _) -> SignalProducer<[User], Error> in | |
SignalProducer { () in | |
Result<[User], Error> { | |
try decoder.decode([User].self, from: data) | |
} | |
} | |
} | |
} | |
// Adapted from the `repeat` operator: https://github.com/ReactiveCocoa/ReactiveSwift/blob/3f4351d04115fd8797802d9b2d17b812cd761602/Sources/SignalProducer.swift#L2270-L2304 | |
return SignalProducer { observer, lifetime in | |
func iterate(since lastSeenUserID: Int?) { | |
fetchUsers(since: lastSeenUserID) | |
.startWithSignal { (signal, signalDisposable) in | |
lifetime += signalDisposable | |
signal.observe { event in | |
switch event { | |
case .value(let users): | |
if let last = users.last, last.id < 300 { | |
// Emit the values we just got | |
observer.send(value: users) | |
// And get the next ones | |
iterate(since: last.id) | |
} else { | |
observer.sendCompleted() | |
} | |
case .failed(let error): | |
observer.send(error: error) | |
case .interrupted: | |
observer.sendInterrupted() | |
case .completed: | |
// Ignore completed events of the child streams | |
break | |
} | |
} | |
} | |
} | |
// Kick off the request for the first page | |
iterate(since: nil) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment