Reputation: 1
Swift As you can see in this swift code I am trying to create a table view for my logout controller. However, I am facing problems with the "log out" button showing as a cell in my view controller. I don't know what the problem is because it builds without any errors and I have gone and checked several times but can't find the problem.
import UIKit
struct SettingsCellModel {
let title: String
let handler: (() -> Void)
}
final class SettingsViewController: UIViewController {
private var tableView: UITableView {
let tableView = UITableView(frame: .zero, style: .grouped)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
return tableView
}
private var data = [[SettingsCellModel]]()
override func viewDidLoad() {
super.viewDidLoad()
configureModels()
view.backgroundColor = .systemBackground
view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
// Do any additional setup after loading the view.
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tableView.frame = view.bounds
}
private func configureModels() {
let section = [SettingsCellModel(title: "Log Out") { [weak self] in
self?.didTapLogOutButton()
}
]
data.append(section)
}
private func didTapLogOutButton() {
let actionSheet = UIAlertController(title: "Log Out", message: "Are you sure you want to log out", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
actionSheet.addAction(UIAlertAction(title: "Log Out", style: .destructive, handler: { _ in
logOut (completion: { success in
DispatchQueue.main.async {
if success {
//present log in
let loginVC = LoginViewController()
loginVC.modalPresentationStyle = .fullScreen
self.present(loginVC, animated: true) {
self.navigationController?.popToRootViewController(animated: false)
self.tabBarController?.selectedIndex = 0
}
}
else {
//error occurred
fatalError("Could not log out user")
}
}
})
}))
actionSheet.popoverPresentationController?.sourceView = tableView
actionSheet.popoverPresentationController?.sourceRect = tableView.bounds
present(actionSheet, animated: true)
}
}
extension SettingsViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = data[indexPath.section][indexPath.row].title
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
data[indexPath.section][indexPath.row].handler()
}
}
Upvotes: 0
Views: 274
Reputation: 20369
Issue is you are using Computed property private var tableView: UITableView {
that means every time you access tableView
in your code its closure is executed (or its value is evaluated), and because you instantiate a new instance of tableView in its closure you receive different instances of tableView in all the 3 statements
view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
hence tableView instance you added as subView is different from the one that has delegate and data source set as self.
What you need
Option 1:
private var tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .grouped)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
return tableView
}()
Option 2: (Preferred)
private lazy var tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .grouped)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
return tableView
}()
Hope it helps
Upvotes: 1