Хотя это тесно связано с вопросом , который Дэвид Смит связал с (и вы также должны это прочитать), стоит ответить отдельно, потому что это другой конкретный вариант использования, и поэтому мы можем поговорить об этом.
Во-первых, представьте, что может сохранить эту переменную. Что бы вы сделали с этим? Какая функция в NetworkManager
может вызвать delegate.didFinishFetchingData
? Как бы вы сгенерировали ResultData
, если не знаете, что это такое?
Дело в том, что это не то, для чего предназначены PAT (протоколы со связанными типами). Это не их цель. Их цель - помочь вам добавить расширения к другим типам или ограничить типы типов, которые можно передавать в универсальные алгоритмы. Для этих целей они невероятно мощные. Но вам нужны дженерики, а не протоколы.
Вместо создания делегатов вы должны использовать универсальные функции для обработки результата конкретного вызова, а не пытаться привязать каждый контроллер представления к определенному типу результата (который в любом случае не очень гибок). Например, самым простым и наименее гибким способом, который все еще дает вам отчеты о проделанной работе:
struct APIClient {
func fetch<Model: Decodable>(_: Model.Type,
with urlRequest: URLRequest,
completion: @escaping (Result<Model, Error>) -> Void)
-> Progress {
let session = URLSession.shared
let task = session.dataTask(with: urlRequest) { (data, _, error) in
if let error = error {
completion(.failure(error))
}
else if let data = data {
let decoder = JSONDecoder()
completion(Result {
try decoder.decode(Model.self, from: data)
})
}
}
task.resume()
return task.progress
}
}
let progress = APIClient().fetch(User.self, with: urlRequest) { user in ... }
Эта структура является основным подходом ко всему этому классу проблем. Это можно сделать намного, гораздо более гибко в зависимости от ваших конкретных потребностей.
(Если ваш didStartFetchingData
метод очень важен, способами, которые Progress
не решают, оставьте комментарий, и я покажу, как реализовать такие вещи. Это не сложно, но этот ответ довольно уже давно.)