【问题标题】:How can I return all the response from API to my Swift app如何将 API 的所有响应返回到我的 Swift 应用程序
【发布时间】:2020-02-26 19:21:53
【问题描述】:

我正在快速学习,我在这里看到了一个示例 https://matteomanferdini.com/network-requests-rest-apis-ios-swift/,我正在尝试更改代码以获取对我有用的东西。

这就是原始代码的样子

struct Wrapper<T: Decodable>: Decodable {
    let items: [T]?
}


protocol NetworkRequest: AnyObject {
    associatedtype ModelType
    func decode(_ data: Data) -> ModelType?
    func load(withCompletion completion: @escaping (ModelType?) -> Void)
}

extension NetworkRequest {
    fileprivate func load(_ url: URLRequest, withCompletion completion: @escaping (ModelType?) -> Void) {
        let session = URLSession(configuration: .default, delegate: nil, delegateQueue: .main)
        let task = session.dataTask(with: url, completionHandler: { [weak self] (data: Data?, response: URLResponse?, error: Error?) -> Void in

            if let error = error {
                print("Error: \(error)")
            }

            guard let data = data else {
                completion(nil)
                return
            }

            completion(self?.decode(data))
        })
        task.resume()
    }
}

class APIRequest<Resource: APIResource> {
    let resource: Resource

    init(resource: Resource) {
        self.resource = resource
    }
}

extension APIRequest: NetworkRequest {
    func decode(_ data: Data) -> [Resource.ModelType]? {
        let wrapper = try? JSONDecoder().decode(Wrapper<Resource.ModelType>.self, from: data)
        return wrapper?.items
    }

    func load(withCompletion completion: @escaping ([Resource.ModelType]?) -> Void) {
        load(resource.request, withCompletion: completion)
    }
}

但我需要将结构 Wrapper 更改为

struct Wrapper<T: Decodable>: Decodable {
    let items: [T]?
    let response: Bool?
    let message: String?
}

并返回 itemsresponsemessage 不仅是 items

【问题讨论】:

    标签: swift api struct urlsession


    【解决方案1】:

    在这种情况下,您根本不需要协议,因为您想要获取根对象。

    这就够了

    struct Wrapper<T: Decodable>: Decodable {
        let items: [T]
        let response: Bool
        let message: String
    }
    
    class NetworkRequest {
        func load<T : Decodable>(_ request: URLRequest, withCompletion completion: @escaping (Result<Wrapper<T>,Error>) -> Void) {
            let session = URLSession(configuration: .default, delegate: nil, delegateQueue: .main)
            let task = session.dataTask(with: request) { data, _, error in
                if let error = error {
                    completion(.failure(error))
                } else {
                    completion( Result {try JSONDecoder().decode(Wrapper<T>.self, from: data!)})
                }
            }
            task.resume()
        }
    }
    

    完成处理程序返回一个Result 对象,成功时返回包装器对象,失败时返回所有错误。

    在包装器结构中声明所有属性为非可选以获取错误消息,并且仅将那些属性更改为可选的,实际上可以是nil

    【讨论】:

      【解决方案2】:

      我这样改代码

      class NetworkRequest<Resource: APIResource> {
      
          let resource: Resource
      
          init(resource: Resource) {
              self.resource = resource
          }
      
          func load(withCompletion completion: @escaping (Result<Wrapper<Resource.ModelType>,Error>) -> Void) {
              let session = URLSession(configuration: .default, delegate: nil, delegateQueue: .main)
              let task = session.dataTask(with: self.resource.request) { data, _, error in
                  if let error = error {
                      completion(.failure(error))
                  } else {
                      completion( Result {try JSONDecoder().decode(Wrapper<Resource.ModelType>.self, from: data!)})
                  }
              }
              task.resume()
          }
      }
      
      struct LoginResource: APIResource {
          typealias ModelType = Token
          let methodPath = "/users/login/"
          let method = "post"
          var params: [String: Any]?
      
          init(username: String, password: String) {
              self.params = ["username":username, "password": password]
          }
      }
      

      在我看来:

      func login() {
              if user == "" || password == "" {
                  self.title_alert = "Info"
                  message_alert = "Test Alert"
                  show_alert = true
                  return
              }
      
              let loginRequest = NetworkRequest(resource: LoginResource(username:user,password:password))
              loginRequest.load { result in
                  switch result {
                      case .failure(let error):
                          print(error)
                      case .success(let data):
                          print(data)
                  }
              }
      
          }
      

      我不知道这是否是最好的方法,但很有效谢谢@vadian

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-24
        • 1970-01-01
        • 2019-04-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多