A UITableView
снабжается данными из ViewModel
с RxSwift Driver
.
Вариант использования - это простой текстовый поиск - когда пользователь вводит строку в SearchBar
API возвращает результаты или нет результатов.Если результатов нет, драйвер возвращает пустой массив.
Проблема в том, что когда результатов нет, а затем поисковый запрос обновляется, поэтому теперь есть результаты, для фреймов ячеек в табличном представлении по умолчанию задано значение(0, 0, 0, 44) - и, таким образом, вообще не показаны.Я устанавливаю начальный backgroundView
для UITableView
, то есть nilled
, когда есть результаты из запроса в части .do {}
.Ячейки внезапно отображаются, когда я прокручиваю вниз, а затем снова вверх, но почему-то изначально они покрываются фоновым представлением, которое должно быть nil
.
Это происходит только при переходе от пустого результата кнепустой результат.Если в ячейках есть результаты, изменение строки запроса и отображение новых результатов работает нормально.
Что может привести к обнулению кадров ячеек и как правильно очистить результаты UITableView
(и показать «Нет»).Сообщение о результатах в UITableView.backgroundView
вместо), если Driver
испускает пустой набор результатов?
ViewModel.swift
var searchText = PublishSubject<String>()
private func getData() -> Driver<[Item]> {
return self.searchText
.filter({ (query) -> Bool in
return query.count > 0
})
.asObservable()
.throttle(0.2, scheduler: MainScheduler.instance)
.distinctUntilChanged()
.flatMapLatest(searchAPI)
.asDriver(onErrorJustReturn: [])
}
ViewController.swift
var viewModel: SearchViewModel!
var tableView: UITableView!
let searchController = UISearchController(searchResultsController: nil)
var searchBar: UISearchBar { return searchController.searchBar }
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
setupBindings()
}
private func setupUI() {
tableView = UITableView(frame: self.view.frame)
tableView.register(SearchResultCell.self, forCellReuseIdentifier: "SearchResultCell")
tableView.rowHeight = 56
tableView.tableHeaderView = searchBar
tableView.separatorStyle = .none
tableView.keyboardDismissMode = .onDrag
tableView.delegate = nil
tableView.dataSource = nil
view.addSubview(tableView)
showMessage(.initial)
configureSearchController()
searchController.searchBar.searchBarStyle = .minimal
}
private func showMessage(_ type: SearchMessage) {
let rect = CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: self.view.bounds.size.width, height: self.view.bounds.size.height))
let emptyMessageLabel = UILabel(frame: rect)
switch type {
case .initial:
emptyMessageLabel.text = "Try searching bla bla"
case .noResult:
emptyMessageLabel.text = "No results found.\nTry searching again"
}
tableView.backgroundView = emptyMessageLabel;
}
extension SearchViewController {
private func setupBindings() {
viewModel.data
.do(onNext: { [weak self] items in
guard let self = self else { return }
self.tableView.backgroundView = nil
if items.count == 0 {
self.showMessage(.noResult)
}
})
.drive(tableView.rx.items(cellIdentifier: "SearchResultCell", cellType: SearchResultCell.self)) { row, item, cell in
cell.label.text = item.title
do {
try _ = cell.imageView.kf.rx.setImage(with: item.imageUrl.asURL()).subscribe()
} catch(let error) {
cell.imageView.image = UIImage.init(named: "DefaultImage")
}
}
.disposed(by: disposeBag)
}
}
SearchResultCell.swift
class SearchResultCell: UITableViewCell {
var nameLabel: UILabel!
var imageView: UIImageView!
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
private func setupUI() {
clipsToBounds = true
autoresizesSubviews = false
nameLabel = UILabel()
imageView = UIImageView(image: nil)
imageView.contentMode = .scaleAspectFit
contentView.addSubview(nameLabel)
contentView.addSubview(imageView)
nameLabel.textColor = .darkGray
nameLabel.font = UIFont.systemFont(ofSize: 15)
}