Swift UIKit Combine - 如何在处理发布者事件时重新加载 tableview?
Swift UIKit Combine - How to reload tableview when handling publisher events?
使用 Combine 和 UIKit,我试图在 viewModel 中包含的数组发生变化时更新我的 tableview。我的tableview的数据源是分开的,因为我想重用这个文件(不同的对象都有一个名字var,所以tableviews会显示一个名字列表)。
视图模型:
class ViewModel {
@Published var items = [ItemViewModel]()
let service = NetworkService()
init() {
fetchItems()
}
func fetchItems() {
service.fetchItems { items in {
self.items = items.map { ItemViewModel([=11=]) }
}
}
数据源:
class GenericDataSource: UITableViewDataSource {
var list = [String]()
func setList(_ list: [String]) {
self.list = list
}
// then the usual tableView datasource boilerplate
}
viewController:
class ViewController: UIViewController {
let viewModel = ViewModel()
let tableDataSouce = GenericDataSource()
var subscriptions = Set<AnyCancellable>()
func setupBinding() {
// I want to: 1) map over viewModel.$items to get [item.name]
// 2) assign the list of names to tableDataSource.list
// 3) reload the tableview so the new values are displayed
}
我不确定要使用什么 Combine 函数。我当前的(工作)代码如下:
func setupBinding() {
viewModel.$items.handleEvents(receiveOutput: { [weak self] items in
self?.dataSource.setList(items.map { [=14=].name })
// dispatch called because I get yelled at for not being on main thread
DispatchQueue.main.async {
self?.itemsTableView.reloadData()
}
})
.sink { _ in }
.store(in: &subscriptions)
}
它有效,但我觉得我在强行使用它。有没有更简洁的方法来执行与当前设置的绑定?
是否有更简洁的方法来设置代码以便绑定更容易?
“更清洁”是主观的,但更“Combine-y”的方式是:
viewModel.$items
.receive(on: DispatchQueue.main)
.sink { [weak self] items in
self?.dataSource.setList(items.map(\.name))
self?.itemsTableView.reloadData()
}
.store(in: &subscriptions)
您还可以使用 .map
运算符来获取名称数组:
.map { [=11=].map(\.name) }
// ...
.sink { [weak self] names in
// ...
}
但我认为这是一个品味问题。
使用 Combine 和 UIKit,我试图在 viewModel 中包含的数组发生变化时更新我的 tableview。我的tableview的数据源是分开的,因为我想重用这个文件(不同的对象都有一个名字var,所以tableviews会显示一个名字列表)。
视图模型:
class ViewModel {
@Published var items = [ItemViewModel]()
let service = NetworkService()
init() {
fetchItems()
}
func fetchItems() {
service.fetchItems { items in {
self.items = items.map { ItemViewModel([=11=]) }
}
}
数据源:
class GenericDataSource: UITableViewDataSource {
var list = [String]()
func setList(_ list: [String]) {
self.list = list
}
// then the usual tableView datasource boilerplate
}
viewController:
class ViewController: UIViewController {
let viewModel = ViewModel()
let tableDataSouce = GenericDataSource()
var subscriptions = Set<AnyCancellable>()
func setupBinding() {
// I want to: 1) map over viewModel.$items to get [item.name]
// 2) assign the list of names to tableDataSource.list
// 3) reload the tableview so the new values are displayed
}
我不确定要使用什么 Combine 函数。我当前的(工作)代码如下:
func setupBinding() {
viewModel.$items.handleEvents(receiveOutput: { [weak self] items in
self?.dataSource.setList(items.map { [=14=].name })
// dispatch called because I get yelled at for not being on main thread
DispatchQueue.main.async {
self?.itemsTableView.reloadData()
}
})
.sink { _ in }
.store(in: &subscriptions)
}
它有效,但我觉得我在强行使用它。有没有更简洁的方法来执行与当前设置的绑定?
是否有更简洁的方法来设置代码以便绑定更容易?
“更清洁”是主观的,但更“Combine-y”的方式是:
viewModel.$items
.receive(on: DispatchQueue.main)
.sink { [weak self] items in
self?.dataSource.setList(items.map(\.name))
self?.itemsTableView.reloadData()
}
.store(in: &subscriptions)
您还可以使用 .map
运算符来获取名称数组:
.map { [=11=].map(\.name) }
// ...
.sink { [weak self] names in
// ...
}
但我认为这是一个品味问题。