【发布时间】:2020-10-08 21:19:23
【问题描述】:
我正在尝试快速从 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后,您需要重新加载表视图。您可以在您的订阅者链中执行此操作 -
@paulw11 你的意思是在数组中吗?即 self.subscriptions = [self.viewModel...collectionView.reloadData
-
我假设您使用的是 diffable 数据源。您如何使用该数据源中的 clubs 数组中的数据?当您将值分配给 clubs 数组时,如何告诉数据源应用新快照?目前,您显示的代码会将检索到的值分配给
clubs,但不会告诉 tableview 对其进行任何处理。 -
您可以在订阅者链中使用
sink闭包在发布者触发时执行代码 -
@Paulw11 我刚刚用数据源代码更新了问题的结尾。
标签: ios swift networking combine urlsession