如何在 Swift 中使用带有 Result 的平面图
Posted
技术标签:
【中文标题】如何在 Swift 中使用带有 Result 的平面图【英文标题】:How to use flatmap with Result in Swift 【发布时间】:2021-05-18 18:48:37 【问题描述】:所以,我有这个从this GitHub gist 复制的函数。
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: $0)
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
【问题讨论】:
我刚刚尝试了Alamofire
v4.9.1 的要点,但在request(_:)
中没有编译错误
我使用的是 5.2.0
然后我得到No type named 'SessionManager' in module 'Alamofire'。在您的问题中提供此类信息可能会很有用
抱歉,我已经解决了所有问题。这只是一张平面地图,我认为这并不重要。
您解决了所有问题,但您仍然提供了要点的链接。你怎么能确定人们会像你一样解决问题?恕我直言,您没有提供minimal, reproducible, example
【参考方案1】:
flatMap(_:)
不接受抛出闭包,而在EndPoint
中,解码是一个抛出闭包:
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($0))
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
,但这可能不是一个好主意。
【讨论】:
【参考方案2】:当你应该使用map
时,你正在使用flatMap
...
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
【讨论】:
以上是关于如何在 Swift 中使用带有 Result 的平面图的主要内容,如果未能解决你的问题,请参考以下文章
如何在 swift setMethodCallHandler 中使用传递的参数 - self?.methodName(result: result)
如何避免在带有 Swift 4 的 iOS 11 中使用带有刷新控件的 @objc?
如何在swift中使用带有completionHandler的UIImageView load()函数