mirror of
https://github.com/ivanvorobei/SwiftUI.git
synced 2026-03-22 01:19:29 +01:00
Combine examples
This commit is contained in:
@@ -1,34 +1,57 @@
|
||||
import SwiftUI
|
||||
import Combine
|
||||
|
||||
enum RequestError: Error {
|
||||
case request(code: Int, error: Error?)
|
||||
case unknown
|
||||
enum URLSessionError: Error {
|
||||
case invalidResponse
|
||||
case serverErrorMessage(statusCode: Int, data: Data)
|
||||
case urlError(URLError)
|
||||
}
|
||||
|
||||
extension URLSession {
|
||||
func send(request: URLRequest) -> AnyPublisher<(data: Data, response: HTTPURLResponse), RequestError> {
|
||||
AnyPublisher<(data: Data, response: HTTPURLResponse), RequestError> { subscriber in
|
||||
let task = self.dataTask(with: request) { data, response, error in
|
||||
DispatchQueue.main.async {
|
||||
let httpReponse = response as? HTTPURLResponse
|
||||
if let data = data, let httpReponse = httpReponse, 200..<300 ~= httpReponse.statusCode {
|
||||
_ = subscriber.receive((data, httpReponse))
|
||||
subscriber.receive(completion: .finished)
|
||||
}
|
||||
else if let httpReponse = httpReponse {
|
||||
subscriber.receive(completion: .failure(.request(code: httpReponse.statusCode, error: error)))
|
||||
}
|
||||
else {
|
||||
subscriber.receive(completion: .failure(.unknown))
|
||||
}
|
||||
}
|
||||
}
|
||||
func send(request: URLRequest) -> AnyPublisher<Data, URLSessionError> {
|
||||
|
||||
subscriber.receive(subscription: AnySubscription(task.cancel))
|
||||
task.resume()
|
||||
}
|
||||
dataTaskPublisher(for: request)
|
||||
.mapError { URLSessionError.urlError($0) }
|
||||
.flatMap { data, response -> AnyPublisher<Data, URLSessionError> in
|
||||
guard let response = response as? HTTPURLResponse else {
|
||||
return .fail(.invalidResponse)
|
||||
}
|
||||
|
||||
guard 200..<300 ~= response.statusCode else {
|
||||
return .fail(.serverErrorMessage(statusCode: response.statusCode,
|
||||
data: data))
|
||||
}
|
||||
|
||||
return .just(data)
|
||||
}.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONDecoder: TopLevelDecoder {}
|
||||
|
||||
extension Publisher {
|
||||
|
||||
/// - seealso: https://twitter.com/peres/status/1136132104020881408
|
||||
func flatMapLatest<T: Publisher>(_ transform: @escaping (Self.Output) -> T) -> Publishers.SwitchToLatest<T, Publishers.Map<Self, T>> where T.Failure == Self.Failure {
|
||||
map(transform).switchToLatest()
|
||||
}
|
||||
}
|
||||
|
||||
extension Publisher {
|
||||
|
||||
static func empty() -> AnyPublisher<Output, Failure> {
|
||||
return Publishers.Empty()
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
static func just(_ output: Output) -> AnyPublisher<Output, Failure> {
|
||||
return Just(output)
|
||||
.catch { _ in AnyPublisher<Output, Failure>.empty() }
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
static func fail(_ error: Failure) -> AnyPublisher<Output, Failure> {
|
||||
return Publishers.Fail(error: error)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,5 +11,11 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
)
|
||||
self.window = window
|
||||
window.makeKeyAndVisible()
|
||||
if let windowScene = scene as? UIWindowScene {
|
||||
let window = UIWindow(windowScene: windowScene)
|
||||
window.rootViewController = UIHostingController(rootView: SearchUserView().environmentObject(SearchUserViewModel()))
|
||||
self.window = window
|
||||
window.makeKeyAndVisible()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,10 +36,10 @@ final class SearchUserViewModel: BindableObject {
|
||||
cancellable = assign
|
||||
|
||||
URLSession.shared.send(request: request)
|
||||
.map { $0.data }
|
||||
.decode(type: SearchUserResponse.self, decoder: JSONDecoder())
|
||||
.map { $0.items }
|
||||
.replaceError(with: [])
|
||||
.receive(on: DispatchQueue.main)
|
||||
.receive(subscriber: assign)
|
||||
}
|
||||
|
||||
@@ -50,10 +50,11 @@ final class SearchUserViewModel: BindableObject {
|
||||
|
||||
let request = URLRequest(url: user.avatar_url)
|
||||
URLSession.shared.send(request: request)
|
||||
.map { UIImage(data: $0.data) }
|
||||
.map { UIImage(data: $0) }
|
||||
.replaceError(with: nil)
|
||||
.eraseToAnyPublisher()
|
||||
.receive(subscriber: Subscribers.Sink<AnyPublisher<UIImage?, Never>> { [weak self] image in
|
||||
.receive(on: DispatchQueue.main)
|
||||
.receive(subscriber: Subscribers.Sink<UIImage?, Never> { [weak self] image in
|
||||
self?.userImages[user] = image
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user