TTBaseUITableViewController
ViewControllerPre-configured UITableViewController base class that extends TTBaseUIViewController's lifecycle hooks into a table-based screen. Provides built-in empty state view, loading indicator, pull-to-refresh, keyboard dismiss on scroll, and correct content insets automatically.
🔄 Lifecycle Methods
Override these methods — all are called at the right time in viewDidLoad/viewWillAppear:
class OrderListVC: TTBaseUITableViewController {
// 1. Register cells, set dataSource/delegate
override func setupData() {
tableView.register(OrderCell.self, forCellReuseIdentifier: "OrderCell")
tableView.dataSource = self
tableView.delegate = self
}
// 2. Apply theming or extra UI setup
override func setupUI() {
navigationItem.title = "My Orders"
}
// 3. Fetch data
override func fetchData() {
showLoadingState()
viewModel.fetchOrders { [weak self] in
self?.hideLoadingState()
self?.tableView.reloadAsyncData()
}
}
// 4. Pull-to-refresh callback
override func onRefreshData(_ sender: UIRefreshControl) {
fetchData()
}
}
🚀 Usage
Empty State
class WishlistVC: TTBaseUITableViewController {
override func setupData() {
viewModel.onDataLoaded = { [weak self] items in
if items.isEmpty {
self?.setEmptyView(
title: "No Items Yet",
message: "Add products to your wishlist to see them here.",
icon: .heart
)
} else {
self?.removeEmptyView()
self?.tableView.reloadAsyncData()
}
}
}
}
Loading State
class ProductListVC: TTBaseUITableViewController {
func loadProducts() {
// Shows spinner overlay on table
showLoadingState()
APIService.getProducts { [weak self] result in
DispatchQueue.main.async {
self?.hideLoadingState()
switch result {
case .success(let items):
self?.products = items
self?.tableView.reloadData()
case .failure(let error):
self?.showErrorAlert(message: error.localizedDescription)
}
}
}
}
}
📖 Override Points
| Method | When Called | Override For |
|---|---|---|
setupData() | viewDidLoad | Cell registration, bindings |
setupUI() | viewDidLoad | Navigation bar, title, bar buttons |
fetchData() | viewWillAppear | Initial data load |
onRefreshData(_:) | Pull-to-refresh triggered | Reload data on pull |
showLoadingState() | Manual | Show activity indicator overlay |
hideLoadingState() | Manual | Remove activity indicator |
setEmptyView(title:message:icon:) | Manual | Show empty state when no data |
removeEmptyView() | Manual | Remove empty state when data arrives |
Pro Tip: Use
TTBaseUITableViewController with the diff-based reload pattern: in fetchData(), show loading, fetch, then call tableView.reloadAsyncData() — all thread-safe. The pull-to-refresh is auto-wired through onRefreshData.