#ios #swift #nsurl #combine
Вопрос:
Я пытаюсь получить данные с помощью API Restcountries, но есть проблема. Когда я пытаюсь извлечь данные, сразу же появляется ошибка:
2021-08-24 17:36:44.851463 0200 Стран[1498:19786] Задача <3FF6E673-52AD-47FE-9342-229E2CE99859>.<3FF6E673-52AD-47FE-9342-229E2CE99859><1> завершена с ошибкой [-999] Домен ошибки=NSURLErrorDomain Код=-999 «отменено» userInfo={NSErrorFailingURLStringKey=https://restcountries.eu/rest/v2/все, NSLocalizedDescription=отменено, NSErrorFailingURLKey=https://restcountries.eu/rest/v2/все}
Это видно каждый раз. Есть идеи, как это решить?
Аписервис:
final class APIService: APIServiceProtocol {
func fetchAllCountries(url: URL) -> AnyPublisher<[Country], APIError> {
let request = URLRequest(url: url)
return URLSession.DataTaskPublisher.init(request: request, session: .shared)
.tryMap { data, response in
guard let httpResponse = response as? HTTPURLResponse, 200..<300 ~= httpResponse.statusCode else {
throw APIError.unknown
}
return data
}
.decode(type: [Country].self, decoder: JSONDecoder())
.mapError { error in
if let error = error as? APIError {
return error
} else {
return APIError.apiError(reason: error.localizedDescription)
}
}
.eraseToAnyPublisher()
}
}
Listviewмодель:
import SwiftUI
import Combine
class ListViewModel: ObservableObject {
private let apiService: APIServiceProtocol
@Published var countries = [Country]()
init(apiService: APIServiceProtocol = APIService()) {
self.apiService = apiService
}
func fetchCountries() {
guard let url = URL(string: "https://restcountries.eu/rest/v2/all") else { return }
let publisher = apiService.fetchAllCountries(url: url)
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
break
case .failure(let error):
print(error.localizedDescription)
}
}, receiveValue: { data in
self.countries = data
print(data)
})
publisher.cancel()
}
}
Ответ №1:
Вы должны назначить издателю надежную ссылку, иначе она мгновенно отменится.
Создайте свойство
var cancellable : AnyCancellable?
назначить
cancellable = apiService.fetchAllCountries(url: url) ...
и отмените публикацию в finished
области
case .finished:
cancellable?.cancel()
Однако, если издатель является одноразовым издателем cancel
, строка является избыточной. Когда издатель отправляет finished
сообщение, конвейер завершается.