Skip to content

Instantly share code, notes, and snippets.

@trickart
Created November 10, 2021 06:28
Show Gist options
  • Save trickart/d7cab1b8ae7ca1ebe13a5c1c66a219f9 to your computer and use it in GitHub Desktop.
Save trickart/d7cab1b8ae7ca1ebe13a5c1c66a219f9 to your computer and use it in GitHub Desktop.
CombineでURLSessionを連結するやつ
import SwiftUI
import Combine
let decoder: JSONDecoder = {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
return decoder
}()
struct User: Decodable, Equatable, Hashable {
let login: String
let id: Int
let avatarUrl: URL
}
enum UsersError: Error {
case empty
}
struct UsersPublisher {
let request: URLRequest = {
var request = URLRequest(url: URL(string: "https://api.github.com/users")!)
request.httpMethod = "GET"
request.allHTTPHeaderFields = ["Accept": "application/vnd.github.v3+json"]
return request
}()
func publish() -> AnyPublisher<[User], Error> {
URLSession.shared
.dataTaskPublisher(for: request)
.map(\.data)
.decode(type: [User].self, decoder: decoder)
.eraseToAnyPublisher()
}
}
enum ImageError: Error {
case url(URLError)
case other
}
struct ImagePublisher {
let url: URL
func publish() -> AnyPublisher<UIImage, Error> {
URLSession.shared
.dataTaskPublisher(for: url)
.map { UIImage(data: $0.data)! }
// 連結するときFailureの型が一致しないとダメっぽい
// https://stackoverflow.com/questions/66713123/why-cant-i-use-flatmap-after-trymap-in-swift-combine/66715459#66715459
.mapError { $0 as Error }
.eraseToAnyPublisher()
}
}
var cancellables: Set<AnyCancellable> = []
UsersPublisher().publish()
.tryMap { users -> URL in
guard let first = users.first else {
throw UsersError.empty
}
return first.avatarUrl
}
.flatMap { url in
ImagePublisher(url: url).publish()
}
.sink(receiveCompletion: { print($0) }, receiveValue: { print($0) })
.store(in: &cancellables)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment