Swift - многоразовый запрос URL с делегатами - PullRequest
1 голос
/ 07 марта 2020

Привет, я новичок в Swift и пытаюсь создать универсальный универсальный шаблон c Диспетчер загрузки для запроса URL, который можно повторно использовать в моем проекте в разных контроллерах представления или повторно использовать в одном V C для другого URL Запрос звонков. Проблема, с которой я столкнулся, заключается в том, как передать тип данных из запроса в диспетчер загрузки, а затем вернуть загруженные данные обратно в V C с соответствующим типом данных. Я могу передать тип данных при вызове downloadRequest, но не могу понять, как передать тип данных обратно в V C через делегат DownloadManagerDelegate. Любая помощь будет очень признателен!

Generi c Менеджер загрузок:

protocol DownloadManagerDelegate {
        func didUpdateData<T: Codable>(modelType: T.Type, downloadedData: T.Type)
}

struct DownloadManager {

    var delegate: DownloadManagerDelegate?

    func downloadRequest<T: Codable>(modelType: T.Type, parameters: [String: Any]) {
       guard let url = URL(string: "https://www.someAPI...") else {return}
       var request = URLRequest(url: url)
       request.httpMethod = "POST"
       request.addValue("application/json", forHTTPHeaderField: "Content-Type")
       guard let httpBodyWithParameters = try? JSONSerialization.data(withJSONObject: parameters, options: []) else 
         {
          print("error")
          return
         }

       request.httpBody = httpBodyWithParameters 
       let session = URLSession.shared
       session.dataTask(with: request) { (data, response, error) in
           if error != nil {
           print("error")
           return
           }

           if let safeData = data {
              if let downloadedData = parseDownloadedData(data: safeData) {
                  self.delegate?.didUpdateData(modelType: modelType, downloadedData: downloadedData)
               }
            }
        }.resume()

   func parseDownloadedData(data: Data) -> T?{
      let decoder = JSONDecoder()
      do {
         let decodedData = try decoder.decode(T.self, from: data)
         return decodedData
      } catch {
         print(error)
         return nil
        }
    } 

 }

Делегат в моем V C:

override func viewDidLoad() {
  super.viewDidLoad()
  downloadManager.delegate = self
}


func didUpdateData(modelType: modelType,downloadedData:downloadedData){
   DispatchQueue.main.async {
     print(downloadedData)
   }
}

Для вызова загрузки downloadRequest:

downloadManager.downloadrequest(modeType: Type1.self, parameters: parameters)

Модель данных определяется как структура:

   struct DataModel1: Codable {
       let ItemID: String
    }

Затем в том же V C я вызываю ту же функцию downloadManager, которая вызывает другой API, который должен возвращать данные для другого типа модели. (определяется как структура)

downloadManager.downloadRequest (modeType: Type2.self, параметры: параметры)

Модель данных определяется как структура:

  struct DataModel2: Codable {
       let EmployeeeID: String
    }

1 Ответ

1 голос
/ 07 марта 2020

В Swift times Protocol / Delegate немного пахнет target- c -i sh.

Я рекомендую обработчик завершения с универсальным типом Result.

Возвращает не обязательный тип generic c в случае успеха и любую ошибку при ошибке.

Принудительное развертывание data безопасно, поскольку если error равно nil, тогда data имеет значение

struct DownloadManager {

    func downloadRequest<T: Decodable>(modelType: T.Type, parameters: [String: Any], completion : @escaping (Result<T, Error>) -> Void) {
        guard let url = URL(string: "https://www.someAPI...") else {return}
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        do {
            let httpBodyWithParameters = try JSONSerialization.data(withJSONObject: parameters)
            request.httpBody = httpBodyWithParameters
            let session = URLSession.shared
            session.dataTask(with: request) { (data, response, error) in
                if let error = error {
                    completion(.failure(error))
                } else {
                    completion( Result { try JSONDecoder().decode(T.self, from: data!)})
                }
            }.resume()
        } catch {
            completion(.failure(error))
        }
    }
}

и использовать его

downloadManager.downloadrequest(modeType: Type1.self, parameters: parameters) { result in 
    switch result {
        case .success(let data): print(data)
        case .failure(let error): print(error)
    }
}
...