-1

My code was working before I change the subclass from UITableViewController to UIViewController.

Reason for switching is I need to add a collectionView on top of my tableView.

But now the cells are not populating. The snapshot is still being called and the users array has its contents.

Not sure why changing to UIViewController made the cells to stop populating.

import UIKit

private let reuseIdentifier = "UserCell"

private typealias UserDataSource = UITableViewDiffableDataSource<SearchController.Section, User>
private typealias UsersSnapshot = NSDiffableDataSourceSnapshot<SearchController.Section, User>

class SearchController: UIViewController {

    // MARK: - Properties
  
    private var tableView = UITableView()

    private var users = [User]()

    private var filteredUsers = [User]()

    private let searchController = UISearchController(searchResultsController: nil)

    private var inSearchMode: Bool {
        return searchController.isActive && !searchController.searchBar.text!.isEmpty
    }

    private var dataSource: UserDataSource!

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()
        configureSearchController()
        configureTableView()
        configureDataSource()
        fetchUsers()
    }

    // MARK: - API

    private func fetchUsers() {
        showLoader(true)
        UserService.fetchUsers { [weak self] users in
            self?.showLoader(false)
            self?.users = users
            self?.createSnapshot(from: users)
        }
    }

    // MARK: - Helpers

    private func configureTableView() {
        view.backgroundColor = .white
        tableView.register(UserCell.self, forCellReuseIdentifier: reuseIdentifier)
        tableView.rowHeight = 64
    }

    private func configureDataSource() {
        dataSource = UserDataSource(tableView: tableView, cellProvider: { (tableView, indexPath, user) -> UITableViewCell? in
            guard let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath) as? UserCell else { fatalError() }
            let user = self.inSearchMode ? self.filteredUsers[indexPath.row] : self.users[indexPath.row]
            cell.viewModel = UserCellViewModel(user: user)
            return cell
        })
    }

    private func configureSearchController() {
        searchController.searchResultsUpdater = self
        searchController.obscuresBackgroundDuringPresentation = false
        searchController.hidesNavigationBarDuringPresentation = false
        searchController.searchBar.placeholder = "Search"
        navigationItem.searchController = searchController
        definesPresentationContext = false
    }

    private func createSnapshot(from users: [User]) {
        var snapshot = UsersSnapshot()
        snapshot.appendSections([.main])
        snapshot.appendItems(users)
        self.dataSource.apply(snapshot, animatingDifferences: false)
    }
}


// MARK: - UITableViewDelegate

extension SearchController {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        guard let nonFilteredUser = dataSource.itemIdentifier(for: indexPath) else { return }
        let user = inSearchMode ? self.filteredUsers[indexPath.row] : nonFilteredUser
        let controller = ProfileController(user: user)
        navigationController?.pushViewController(controller, animated: true)
    }
}

// MARK: - UISearchResultsUpdating

extension SearchController: UISearchResultsUpdating {
    func updateSearchResults(for searchController: UISearchController) {
        guard let searchText = searchController.searchBar.text?.lowercased() else { return }

        filteredUsers = users.filter({$0.username.lowercased().contains(searchText)
                        || $0.fullname.lowercased().contains(searchText) })

        let users = searchText.isEmpty ? self.users : filteredUsers

        self.createSnapshot(from: users)
    }
}

// MARK: - Sections

extension SearchController {
    fileprivate enum Section {
        case main
    }
}
Dreiohc
  • 317
  • 2
  • 12
  • 1
    The most significant change is that `dataSource` and `delegate` of the table view are not implicitly connected to the controller. – vadian Apr 08 '21 at 18:17
  • What do you mean by not connected? – Dreiohc Apr 09 '21 at 04:14
  • Somewhere to have to set `dataSource` and `delegate` to `self`. And you have to adopt the corrsponding protocols. – vadian Apr 09 '21 at 04:30
  • Diffable tableviews actually doesn't need to conform to those unless you need to add didSelectCell method to which is not the issue here. I solved it by checking the view hierarchy, the table view was actually not added to the frame so there are actually no tableView in view hierarchy when I switched to UIViewController subclass. – Dreiohc Apr 09 '21 at 04:54

1 Answers1

-1

The table view was actually not added to the frame so there are actually no tableView in view hierarchy when I switched to UIViewController subclass. I add this in viewDidLoad and it's now visible.

Forgot that UIViewController doesn't automatically add a tableView in the view like UITableViewController subclass.

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()
        configureSearchController()
        configureTableView()
        configureDataSource()
        fetchUsers()
    
        view.addSubview(tableView) // What I've missed to add.
        tableView.frame = view.bounds
    }
Dreiohc
  • 317
  • 2
  • 12