Skip to content

Instantly share code, notes, and snippets.

@jasdev
Last active May 1, 2020 02:24
Show Gist options
  • Save jasdev/3f41d757d9dab846405fb09ac5ac98a8 to your computer and use it in GitHub Desktop.
Save jasdev/3f41d757d9dab846405fb09ac5ac98a8 to your computer and use it in GitHub Desktop.
Cold publisher example.
import Foundation /// (1) Also need to bring in Foundation.
enum SomeError: Error {
case anError
}
let requestURL = URL(string: "https://picsum.photos/v2/list")! /// (2) [Following an exercise](https://github.com/objcio/thinking-in-swiftui-sample-code/blob/c48c352529776175dd6d9ee857dae67edeecd7a2/Exercises/Chapter%2002/ImageLoading/ImageLoading/ContentView.swift#L47)
/// from objc.io’s Thinking in Swift UI.
struct Photo: Decodable { /// (3) The endpoint returns an array of photo objects, so, let’s parse
/// them out and only hold onto each identifier (again, for sake of example).
var id: String
}
var attemptCount = 1 /// (4) Teeing up the ability to deterministically fail.
/// We’ll use this as a flag to fail on odd counts and succeed on evens.
let coldPublisher: AnyPublisher<[Photo], Error> = URLSession.shared
.dataTaskPublisher(for: requestURL)
.map(\.data)
.decode(type: [Photo].self, decoder: JSONDecoder())
.tryMap {
defer { attemptCount += 1 } /// (5) Bumping the count.
if attemptCount.isMultiple(of: 2) { /// (6) Succeed on even-counted attempts, else, `throw`.
return $0
} else {
throw SomeError.anError
}
}
.eraseToAnyPublisher() /// (7) We need to erase and type annotate because
/// `throw`ing in the `tryMap` trips up the compiler.
let subscriber = AnySubscriber<[Photo], Error>(
receiveSubscription: { $0.request(.max(1)) }, /// (8) Request a single value since this
/// request will only ever return that many payloads-worth of JSON.
receiveValue: { print($0.map(\.id)); return .none }, /// (9) Log out the `id`s and
/// request no further values.
receiveCompletion: { print($0) }
)
coldPublisher
.subscribe(subscriber)
coldPublisher
.subscribe(subscriber)
/// (10) Output, note that even though the first attempt error’d out,
/// the second subscription carried on as if it hadn’t.
/// ```none
/// failure(__lldb_expr_40.SomeError.anError)
/// ["0", "1", "10", "100", "1000", "1001", "1002", "1003", "1004", "1005", "1006", "1008", "1009", "101", "1010", "1011", "1012", "1013", "1014", "1015", "1016", "1018", "1019", "102", "1020", "1021", "1022", "1023", "1024", "1025"]
/// finished
/// ```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment