Самая трудная задача, с которой я сталкиваюсь, это знать правильную терминологию для поиска. Я привык к SwiftUI как к простому способу создания приложения в кратчайшие сроки. В этом проекте я должен использовать UIKit и для этой конкретной задачи.
Внутри контроллера представления я создал tableView
:
private let tableView: UITableView = {
let table = UITableView()
table.register(ProfileCell.self, forCellReuseIdentifier: ProfileCell.identifier)
return table
}()
Позже перезагружаю данные внутри viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
Task {
do {
try await viewModel.getProfiles()
// Here I reload the table when data comes in
self.tableView.reloadData()
} catch {
print(error)
}
}
view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
}
Итак, что такое viewModel
? В SwiftUI я привык иметь это внутри структуры представления:
@ObservedObject var viewModel = ProfilesViewModel()
... и это то, что у меня есть внутри моего контроллера представления. Я искал:
..и многое другое, но отмечу, что мне было полезно «собирать по кусочкам».
В том же контроллере я showMyViewControllerInACustomizedSheet, который теперь использует UIHostingController
:
private func showMyViewControllerInACustomizedSheet() {
// A SwiftUI view along with viewModel being passed in
let view = ProfilesMenu(viewModel: viewModel)
let viewControllerToPresent = UIHostingController(rootView: view)
if let sheet = viewControllerToPresent.sheetPresentationController {
sheet.detents = [.medium(), .large()]
sheet.largestUndimmedDetentIdentifier = .medium
sheet.prefersScrollingExpandsWhenScrolledToEdge = false
sheet.prefersEdgeAttachedInCompactHeight = true
sheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true
}
present(viewControllerToPresent, animated: true, completion: nil)
}
Для ProfilesViewModel:
class ProfilesViewModel: ObservableObject {
// ProfilesResponse is omitted
@Published var profiles = [ProfilesResponse]()
public func getProfiles(endpoint: String? = nil) async throws -> Void {
// After getting the data, I set the profiles variable
self.profiles = [..]
}
}
Всякий раз, когда я звоню try await viewModel.getProfiles(endpoint: "...")
из ProfileMenu
, я хочу перезагрузить tableView. Какая дополнительная настройка требуется?
Привет @vadian. Я уже видел это слово «Комбинировать». Спасибо. Я почитаю, как он используется.
@Published
является частью Combine Framework. Вам нужен подписчик, чтобы иметь возможность прослушивать изменения.
@vadian Нашел это, потому что вы упомянули Combine: swiftbysundell.com/articles/published-properties-in-swift Спасибо за подсказку.
Вы реализовали функции func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
и func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
?
Независимо от того, обернуты ли они Published
, это не должно препятствовать отображению данных в представлении, они просто не используются UIKit так, как это происходит со SwiftUI. У меня такое чувство, что ваша проблема связана с реализацией источника данных.
Привет. Да, это нужно было реализовать, но мне нужен был способ перезагрузить таблицу при изменении viewModel
. Я опубликовал ответ, который работает.
В комментариях Вадиан упомянул «Комбайн», где я провел поиск в Google и нашел это. Что работает, для базовой демонстрации:
[..]
import Combine
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let viewModel = ProfilesViewModel()
private var cancellable: AnyCancellable?
override func viewDidLoad() {
super.viewDidLoad()
Task {
do {
try await viewModel.getProfiles()
// Remove this
// self.tableView.reloadData()
} catch {
print(error)
}
}
view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
// Add this
cancellable = viewModel.objectWillChange.sink(receiveValue: { [weak self] in
self?.render()
})
}
// Also add this
private func render() {
// TODO: Implement failures...
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
...
}
objectWillChange
был ключом к моей проблеме.
Только
SwiftUI
просмотры реагируют на@Published
неявно. ВUIKit
вы можете использоватьCombine
и замыкание обратного вызова.