如何使用Swift 5 URLSession中引入的新Result类型?

时间:2019-04-25 10:44:49

标签: urlsession swift5

Swift 5引入了新的Result类型来处理异步函数的结果。我想知道将这种新的结果类型用于URLSession的方法。

  

我有以下代码。

img1 = cv2.imread('Edged_img.jpg', 0)
img1 = cv2.cvtColor(img1, cv2.COLOR_GRAY2BGR)

如何使用swift 5 Result类型重写此函数?

2 个答案:

答案 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上的.successerror上的.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