Swift - 如何从 REST API 解码 json

Swift - How do I decode json from a REST API

我正在尝试从 swift 中的 REST API 获取 GET。当我使用打印语句 (print(clubs)) 时,我看到了正确格式的预期响应。但是在 VC 中给了我一个空数组。

这是与 API

对话的代码
extension ClubAPI {

    public enum ClubError: Error {
        case unknown(message: String)
    }

    func getClubs(completion: @escaping ((Result<[Club], ClubError>) -> Void)) {
        let baseURL = self.configuration.baseURL
        let endPoint = baseURL.appendingPathComponent("/club")
        print(endPoint)
        API.shared.httpClient.get(endPoint) { (result) in
            switch result {
            case .success(let response):
                let clubs = (try? JSONDecoder().decode([Club].self, from: response.data)) ?? []
                print(clubs)
                completion(.success(clubs))
            case .failure(let error):
                completion(.failure(.unknown(message: error.localizedDescription)))
            }
        }
    }

}

这里是 VC

中的代码
private class ClubViewModel {
    @Published private(set) var clubs = [Club]()
    @Published private(set) var error: String?

    func refresh() {
        ClubAPI.shared.getClubs { (result) in
            switch result {
            case .success(let club):
                print("We have \(club.count)")
                self.clubs = club
                print("we have \(club.count)")
            case .failure(let error):
                self.error = error.localizedDescription
            }
        }
    }
}

这是视图控制器代码(扩展前)

class ClubViewController: UIViewController {
    private var clubs = [Club]()
    private var subscriptions = Set<AnyCancellable>()
    private lazy var dataSource = makeDataSource()

    enum Section {
        case main
    }
    private var errorMessage: String? {
        didSet {

        }
    }
    private let viewModel = ClubViewModel()
    @IBOutlet private weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.subscriptions = [
            self.viewModel.$clubs.assign(to: \.clubs, on: self),
            self.viewModel.$error.assign(to: \.errorMessage, on: self)
        ]

        applySnapshot(animatingDifferences: false)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.viewModel.refresh()
    }



}




extension ClubViewController {
    typealias DataSource = UITableViewDiffableDataSource<Section, Club>
    typealias Snapshot = NSDiffableDataSourceSnapshot<Section, Club>
    func applySnapshot(animatingDifferences: Bool = true) {
        // Create a snapshot object.
        var snapshot = Snapshot()
        // Add the section
        snapshot.appendSections([.main])
        // Add the player array
        snapshot.appendItems(clubs)
        print(clubs.count)

        // Tell the dataSource about the latest snapshot so it can update and animate.
        dataSource.apply(snapshot, animatingDifferences: animatingDifferences)
    }

    func makeDataSource() -> DataSource {
        let dataSource = DataSource(tableView: tableView) { (tableView, indexPath, club) -> UITableViewCell? in
            let cell = tableView.dequeueReusableCell(withIdentifier: "ClubCell", for: indexPath)
            let club = self.clubs[indexPath.row]
            print("The name is \(club.name)")
            cell.textLabel?.text = club.name
            return cell
        }
        return dataSource
    }
}

获取 clubs 后,您需要将新快照应用于 table 视图。您当前的订阅者只是为 clubs 分配了一个值,仅此而已。

您可以使用 sink 订阅者分配新的 clubs 值,然后调用 applySnapshot。您需要确保这发生在主队列上,因此您可以使用 receive(on:).

self.subscriptions = [
    self.viewModel.$clubs.receive(on: RunLoop.main).sink { clubs in
        self.clubs = clubs
        self.applySnapshot()
    },
    self.viewModel.$error.assign(to: \.errorMessage, on: self)
]