Swift 5引入了新的Result类型来处理异步函数的结果。我想知道将这种新的结果类型用于URLSession的方法。
我有以下代码。
img1 = cv2.imread('Edged_img.jpg', 0)
img1 = cv2.cvtColor(img1, cv2.COLOR_GRAY2BGR)
如何使用swift 5 Result类型重写此函数?
答案 0 :(得分:3)
我在URLSession上写了一个扩展,抽象了错误处理和解码的样板代码。
{% thumbnail model.image "1200x630" crop="top" upscale="True" as im %}
enum URLError: Error {
case noData, decodingError
}
extension URLSession {
/// A type safe URL loader that either completes with success value or error with Error
func jsonDecodableTask<T: Decodable>(with url: URLRequest, decoder: JSONDecoder = JSONDecoder(), completion: @escaping (Result<T, Error>) -> Void) -> URLSessionDataTask {
self.dataTask(with: url) { (data, response, error) in
DispatchQueue.main.async {
guard error == nil else {
completion(.failure(error!))
return
}
guard let data = data, let _ = response else {
completion(.failure(URLError.noData))
return
}
do {
let decoded = try decoder.decode(T.self, from: data)
completion(.success(decoded))
} catch {
completion(.failure(error))
}
}
}
}
func jsonDecodableTask<T: Decodable>(with url: URL, decoder: JSONDecoder = JSONDecoder(), completion: @escaping (Result<T, Error>) -> Void) -> URLSessionDataTask {
self.jsonDecodableTask(with: URLRequest(url: url), decoder: decoder, completion: completion)
}
}
您还可以像这样通过自己的struct Person: Codable {
let name: String
let age: Int
}
let url = URL(string: "https://abcd.com")!
URLSession.shared.jsonDecodableTask(with: url) { (result: Result<Person, Error>) in
switch result {
case .success(let person):
print("Person \(person.name)")
case .failure(let error):
print(error)
}
}.resume()
JSONDecoder
答案 1 :(得分:0)
您要创建一个enum
来指定结果中可能出现的情况(例如成功或失败)。然后,将完成方式添加到getCategorByAPI()
类型的Result<Data, Error>
方法中。从那里开始,在url会话中,您将调用完成处理程序,以传入data
上的.success
或error
上的.failure
。
您还可以做一些很酷的事情,例如覆盖Result的get()
方法和扩展Result
来解码数据:D
签出:
enum Result<Success, Error: Swift.Error> {
case success(Success)
case failure(Error)
}
// override the Result.get() method
extension Result {
func get() throws -> Success {
switch self {
case .success(let value):
return value
case .failure(let error):
throw error
}
}
}
// use generics - this is where you can decode your data
extension Result where Success == Data {
func decoded<T: Decodable>(using decoder: JSONDecoder = .init()) throws -> T {
let data = try get()
return try decoder.decode(T.self, from: data)
}
}
func getCategorByAPI(completion: (Result<Data, Error>) -> Void)
{
// You might want to stick this into another method
let url = URL(string: URLManager.aPIBaseURL+"category")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
completion(.failure(error))
return
}
if !(200...299).contains(httpResponse.statusCode) && !(httpResponse.statusCode == 304) {
let httpError = // ... convert httpResponse.statusCode into a more readable error
completion(.failure(httpError))
}
if let data = data {
completion(.success(data))
}
}.resume()
}
我没有测试上面的内容,但是在当前项目中实现了类似的功能。这是我阅读的一些文章,以了解如何实现:
https://www.hackingwithswift.com/articles/161/how-to-use-result-in-swift
https://medium.com/@pavlepesic/how-to-use-swift-5-result-with-codable-protocol-824c9a951af9