Быстрое объединение: завершено с ошибкой [-999] Домен ошибки=NSURLErrorDomain Код=-999 «отменено»

#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 сообщение, конвейер завершается.