Swift - 合并订阅未被调用

Swift - Combine subscription not being called

最近尝试使用freshOS/Networkingswift包。

而且我读了好几遍 README 文件,但我无法让它与我一起工作。我正在尝试获取使用 public API 服务的国家/地区列表,这就是我所做的:

型号

import Foundation
import Networking

struct CountryModel: Codable {
    let error: Bool
    let msg: String
    let data: [Country]
}

struct Country: Codable {
    let name: String
    let Iso3: String
}

extension Country: NetworkingJSONDecodable {}
extension CountryModel: NetworkingJSONDecodable {}

/* 
Output
{
     "error":false,
     "msg":"countries and ISO codes retrieved",
     "data":[
          {
               "name":"Afghanistan",
               "Iso2":"AF",
               "Iso3":"AFG"
          }
     ]
}
*/

View Controller + print(data) in callAPI() 函数不打印

    override func viewDidLoad() {
        super.viewDidLoad()
        
        configureUI()
        callAPI()
        
    }

    fileprivate func configureUI() {
        title = "Choose Country"
        
        view.addSubview(tableView)
        tableView.delegate = self
        tableView.dataSource = self
        tableView.frame = view.bounds
    }

    fileprivate func callAPI() {
        let countriesService = CountriesApi()
        var cancellable = Set<AnyCancellable>()
        
        countriesService.countries().sink(receiveCompletion: { completion in
            switch completion {
            case .finished:
                print("finished") // not printing
                break
            case .failure(let error):
                print(error.localizedDescription)
            }
        }) { data in
            print(data) // not printing
            self.countriesData = data
        }.store(in: &cancellable)
    }

国家API()

struct CountriesApi: NetworkingService {
    
    let network = NetworkingClient(baseURL: "https://countriesnow.space/api/v0.1")
    
    // Create
    func create(country c: Country) -> AnyPublisher<Country, Error> {
        post("/countries/create", params: ["name" : c.name, "Iso3" : c.Iso3])
    }
    
    // Read
    func fetch(country c: Country) -> AnyPublisher<Country, Error> {
        get("/countries/\(c.Iso3)")
    }
    
    // Update
    func update(country c: Country) -> AnyPublisher<Country, Error> {
        put("/countries/\(c.Iso3)", params: ["name" : c.name, "Iso3" : c.Iso3])
    }
    
    // Delete
    func delete(country c: Country) -> AnyPublisher<Void, Error> {
        delete("/countries/\(c.Iso3)")
    }
    
    func countries() -> AnyPublisher<[CountryModel], Error> {
        get("/countries/iso")
    }
}

我希望有人能帮助解决我所缺少的。

问题出在您的 callAPI() 函数上,如果您将代码更改为:

    fileprivate func callAPI() {
        let countriesService = CountriesApi()
        var cancellable = Set<AnyCancellable>()
        
        countriesService.countries()
            .print("debugging")
            .sink(receiveCompletion: { completion in
                switch completion {
                case .finished:
                    print("finished") // not printing
                    break
                case .failure(let error):
                    print(error.localizedDescription)
                }
            }) { data in
                print(data) // not printing
                self.countriesData = data
            }.store(in: &cancellable)
    }

请注意,我刚刚添加了行 print("debugging")

如果您 运行 这样做,您可以在控制台中看到您的订阅立即被取消。

debugging: receive cancel

为什么?因为你的“可取消”或“订阅”只存在于你的功能范围内,因此,它会立即被释放。

您可以做的是在 ViewController 中添加设置为 属性 的可取消项,如下所示:

final class ViewController: UIViewController {
    
    private var cancellable = Set<AnyCancellable>()
    
    fileprivate func callAPI() {
        // the code you had without the set
        let countriesService = CountriesApi()
        
        countriesService.countries().sink(receiveCompletion: { completion in
            switch completion {
            case .finished:
                print("finished") // not printing
                break
            case .failure(let error):
                print(error.localizedDescription)
            }
        }) { data in
            print(data) // not printing
            self.countriesData = data
        }.store(in: &cancellable)
    }
    
}