Swift 合并:完成,出现错误 [-999] 错误域=NSURLErrorDomain 代码=-999 "cancelled"

Swift Combine: finished with error [-999] Error Domain=NSURLErrorDomain Code=-999 "cancelled"

我正在尝试通过 Restcountries API 获取数据,但是出现问题。当我尝试获取数据时,错误立即出现:

2021-08-24 17:36:44.851463+0200 Countries[1498:19786] Task <3FF6E673-52AD-47FE-9342-229E2CE99859>.<1> finished with error [-999] Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLStringKey=https://restcountries.eu/rest/v2/all, NSLocalizedDescription=cancelled, NSErrorFailingURLKey=https://restcountries.eu/rest/v2/all}

每次都显示。知道如何解决吗?

API服务:

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()
}

}

列表视图模型:

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()
    }
    
}

您必须将发布者分配给 strong 引用,否则它会立即取消。

创建 属性

var cancellable : AnyCancellable?

分配

cancellable = apiService.fetchAllCountries(url: url) ...

并取消 finished 范围内的发布者

case .finished:
    cancellable?.cancel()

但是,如果发布者是 一次性 发布者,则 cancel 行是多余的。当发布者发出 finished 时,管道终止。