如何在 Swift 中使用带有结果的平面图
How to use flatmap with Result in Swift
所以,我有这个函数,它是从 this GitHub 要点复制的。
protocol ClientProtocol {
func request<Response: Codable>(_ endpoint: Endpoint<Response>)-> Single<Response>
}
final class Client: ClientProtocol {
private let manager: Alamofire.Session
private let baseURL = URL(string: "http://192.168.20:8080")!
private let queue = DispatchQueue(label: "<your_queue_label>")
init(accessToken: String) {
let configuration = URLSessionConfiguration.default
configuration.headers.add(name: "Authorization", value: "Bearer \(accessToken)")
configuration.timeoutIntervalForRequest = 15
self.manager = Alamofire.Session.init(configuration: configuration)
//self.manager.retrier = OAuth2Retrier()
}
func request<Response>(_ endpoint: Endpoint<Response>) -> Single<Response> {
return Single<Response>.create { observer in
let request = self.manager.request(
self.url(path: endpoint.path),
method: httpMethod(from: endpoint.method),
parameters: endpoint.parameters
)
request
.validate()
.responseData(queue: self.queue) { response in
let result: Result<Response, AFError> = response.result.flatMap(endpoint.decode)
switch result {
case let .success(val): observer(.success(val))
case let .failure(err): observer(.error(err))
}
}
return Disposables.create {
request.cancel()
}
}
}
private func url(path: Path) -> URL {
return baseURL.appendingPathComponent(path)
}
}
private func httpMethod(from method: Method) -> Alamofire.HTTPMethod {
switch method {
case .get: return .get
case .post: return .post
case .put: return .put
case .patch: return .patch
case .delete: return .delete
}
}
private class OAuth2Retrier: Alamofire.RequestRetrier {
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
if (error as? AFError)?.responseCode == 401 {
// TODO: implement your Auth2 refresh flow
// See https://github.com/Alamofire/Alamofire#adapting-and-retrying-requests
}
// completion(false, 0)
}
}
端点
// MARK: Defines
typealias Parameters = [String: Any]
typealias Path = String
enum Method {
case get, post, put, patch, delete
}
// MARK: Endpoint
final class Endpoint<Response> {
let method: Method
let path: Path
let parameters: Parameters?
let decode: (Data) throws -> Response
init(method: Method = .get, path: Path, parameters: Parameters? = nil, decode: @escaping (Data) throws -> Response) {
self.method = method
self.path = path
self.parameters = parameters
self.decode = decode
}
}
// MARK: Convenience
extension Endpoint where Response: Swift.Decodable {
convenience init(method: Method = .get, path: Path, parameters: Parameters? = nil) {
self.init(method: method, path: path, parameters: parameters) {
try JSONDecoder().decode(Response.self, from: [=12=])
}
}
}
extension Endpoint where Response == Void {
convenience init(method: Method = .get, path: Path, parameters: Parameters? = nil) {
self.init(method: method, path: path, parameters: parameters, decode: { _ in () })
}
}
在let result = response.result.flatMap(endpoint.decode)
xCode 正在投掷
Type of expression is ambiguous without more context
response.result
的类型是Result<Data, AFError>
我想将其平面映射到 Result< Response, AFError>
。
我试过了
let result = response.result.flatMap { (data) -> Result<Response, AFError> in
// don't know what to put here
}
flatMap(_:)
不采用抛出闭包,在 EndPoint
中,decode 是一个抛出闭包:
let decode: (Data) throws -> Response
尝试捕获错误:
func request<Response>(_ endpoint: Endpoint<Response>) -> Single<Response> {
return Single<Response>.create { observer in
let request = self.manager.request(
self.url(path: endpoint.path),
method: httpMethod(from: endpoint.method),
parameters: endpoint.parameters
)
request
.validate()
.responseData(queue: self.queue) { response in
let result: Result<Response, AFError> = response.result.flatMap {
do {
return Result<Response, AFError>.success(try endpoint.decode([=11=]))
} catch let error as AFError {
return Result<Response, AFError>.failure(error)
} catch {
fatalError(error.localizedDescription)
}
}
switch result {
case let .success(val): observer(.success(val))
case let .failure(err): observer(.failure(err))
}
}
return Disposables.create {
request.cancel()
}
}
}
备注
由于您似乎只对 AFError
感兴趣,此代码将调用 fatalError
不过这可能不是一个好主意。
你在使用 flatMap
而你应该使用 map
...
func example(response: Response, endpoint: Endpoint<Thing>) {
let result = response.result.map(endpoint.decode)
}
struct Response {
let result: Result<Data, Error>
}
struct Endpoint<T> {
func decode(_ data: Data) -> T { fatalError() }
}
struct Thing { }
所以,我有这个函数,它是从 this GitHub 要点复制的。
protocol ClientProtocol {
func request<Response: Codable>(_ endpoint: Endpoint<Response>)-> Single<Response>
}
final class Client: ClientProtocol {
private let manager: Alamofire.Session
private let baseURL = URL(string: "http://192.168.20:8080")!
private let queue = DispatchQueue(label: "<your_queue_label>")
init(accessToken: String) {
let configuration = URLSessionConfiguration.default
configuration.headers.add(name: "Authorization", value: "Bearer \(accessToken)")
configuration.timeoutIntervalForRequest = 15
self.manager = Alamofire.Session.init(configuration: configuration)
//self.manager.retrier = OAuth2Retrier()
}
func request<Response>(_ endpoint: Endpoint<Response>) -> Single<Response> {
return Single<Response>.create { observer in
let request = self.manager.request(
self.url(path: endpoint.path),
method: httpMethod(from: endpoint.method),
parameters: endpoint.parameters
)
request
.validate()
.responseData(queue: self.queue) { response in
let result: Result<Response, AFError> = response.result.flatMap(endpoint.decode)
switch result {
case let .success(val): observer(.success(val))
case let .failure(err): observer(.error(err))
}
}
return Disposables.create {
request.cancel()
}
}
}
private func url(path: Path) -> URL {
return baseURL.appendingPathComponent(path)
}
}
private func httpMethod(from method: Method) -> Alamofire.HTTPMethod {
switch method {
case .get: return .get
case .post: return .post
case .put: return .put
case .patch: return .patch
case .delete: return .delete
}
}
private class OAuth2Retrier: Alamofire.RequestRetrier {
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
if (error as? AFError)?.responseCode == 401 {
// TODO: implement your Auth2 refresh flow
// See https://github.com/Alamofire/Alamofire#adapting-and-retrying-requests
}
// completion(false, 0)
}
}
端点
// MARK: Defines
typealias Parameters = [String: Any]
typealias Path = String
enum Method {
case get, post, put, patch, delete
}
// MARK: Endpoint
final class Endpoint<Response> {
let method: Method
let path: Path
let parameters: Parameters?
let decode: (Data) throws -> Response
init(method: Method = .get, path: Path, parameters: Parameters? = nil, decode: @escaping (Data) throws -> Response) {
self.method = method
self.path = path
self.parameters = parameters
self.decode = decode
}
}
// MARK: Convenience
extension Endpoint where Response: Swift.Decodable {
convenience init(method: Method = .get, path: Path, parameters: Parameters? = nil) {
self.init(method: method, path: path, parameters: parameters) {
try JSONDecoder().decode(Response.self, from: [=12=])
}
}
}
extension Endpoint where Response == Void {
convenience init(method: Method = .get, path: Path, parameters: Parameters? = nil) {
self.init(method: method, path: path, parameters: parameters, decode: { _ in () })
}
}
在let result = response.result.flatMap(endpoint.decode)
xCode 正在投掷
Type of expression is ambiguous without more context
response.result
的类型是Result<Data, AFError>
我想将其平面映射到 Result< Response, AFError>
。
我试过了
let result = response.result.flatMap { (data) -> Result<Response, AFError> in
// don't know what to put here
}
flatMap(_:)
不采用抛出闭包,在 EndPoint
中,decode 是一个抛出闭包:
let decode: (Data) throws -> Response
尝试捕获错误:
func request<Response>(_ endpoint: Endpoint<Response>) -> Single<Response> {
return Single<Response>.create { observer in
let request = self.manager.request(
self.url(path: endpoint.path),
method: httpMethod(from: endpoint.method),
parameters: endpoint.parameters
)
request
.validate()
.responseData(queue: self.queue) { response in
let result: Result<Response, AFError> = response.result.flatMap {
do {
return Result<Response, AFError>.success(try endpoint.decode([=11=]))
} catch let error as AFError {
return Result<Response, AFError>.failure(error)
} catch {
fatalError(error.localizedDescription)
}
}
switch result {
case let .success(val): observer(.success(val))
case let .failure(err): observer(.failure(err))
}
}
return Disposables.create {
request.cancel()
}
}
}
备注
由于您似乎只对 AFError
感兴趣,此代码将调用 fatalError
不过这可能不是一个好主意。
你在使用 flatMap
而你应该使用 map
...
func example(response: Response, endpoint: Endpoint<Thing>) {
let result = response.result.map(endpoint.decode)
}
struct Response {
let result: Result<Data, Error>
}
struct Endpoint<T> {
func decode(_ data: Data) -> T { fatalError() }
}
struct Thing { }