oivlis111
oivlis111

Reputation: 55

Swift 4: UITableView dataSource isn't working

I'm trying to add some data to a UITableView object. My problem is that none of the methods in my data source object is called during runtime. I already checked that the UITableView itself is displayed. When I call providerTable.reloadData() just the numberOfSections(in tableView: UITableView) -> Int and tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int method is called, but never tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

import UIKit

class ProviderViewController: UIViewController {

    let navigationBar = { () -> UINavigationBar in
        let bar = UINavigationBar()
        bar.setItems([
            { () -> UINavigationItem in
                let item = UINavigationItem()
                item.title = "a title"
                return item
            }()
        ], animated: false)
        bar.translatesAutoresizingMaskIntoConstraints = false
        return bar
    }()
    let providerTable = { () -> UITableView in
        let providerDataSource = ProviderTableDataSource()

        let table = UITableView()
        table.dataSource = providerDataSource
        table.translatesAutoresizingMaskIntoConstraints = false
        table.register(ProviderTableViewCell.self, forCellReuseIdentifier: "providerCell")
        return table
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.setupWindow()
    }

    func setupWindow() -> Void {
        view.backgroundColor = .white

        view.addSubview(navigationBar)
        view.addSubview(providerTable)

        // Set constraints
        var constraints = [NSLayoutConstraint]()
        // navbar
        constraints.append(NSLayoutConstraint(item: navigationBar,
                                              attribute: .width,
                                              relatedBy: .equal,
                                              toItem: view,
                                              attribute: .width,
                                              multiplier: 1,
                                              constant: 0))
        constraints.append(NSLayoutConstraint(item: navigationBar,
                                              attribute: .left,
                                              relatedBy: .equal,
                                              toItem: view,
                                              attribute: .left,
                                              multiplier: 1,
                                              constant: 0))
        constraints.append(NSLayoutConstraint(item: navigationBar,
                                              attribute: .top,
                                              relatedBy: .equal,
                                              toItem: view.safeAreaLayoutGuide,
                                              attribute: .top,
                                              multiplier: 1,
                                              constant: 0))
        // provider table
        constraints.append(NSLayoutConstraint(item: providerTable,
                                              attribute: .width,
                                              relatedBy: .equal,
                                              toItem: view,
                                              attribute: .width,
                                              multiplier: 1,
                                              constant: 0))
        constraints.append(NSLayoutConstraint(item: providerTable,
                                              attribute: .left,
                                              relatedBy: .equal,
                                              toItem: view,
                                              attribute: .left,
                                              multiplier: 1,
                                              constant: 0))
        constraints.append(NSLayoutConstraint(item: providerTable,
                                              attribute: .top,
                                              relatedBy: .equal,
                                              toItem: navigationBar,
                                              attribute: .bottom,
                                              multiplier: 1,
                                              constant: 0))
        constraints.append(NSLayoutConstraint(item: providerTable,
                                              attribute: .bottom,
                                              relatedBy: .equal,
                                              toItem: view,
                                              attribute: .bottom,
                                              multiplier: 1,
                                              constant: 0))
        // activate constraints
        view.addConstraints(constraints)
    }

}

The data source object: import UIKit

class ProviderTableDataSource: NSObject, UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "providerCell", for: indexPath) as! ProviderTableViewCell
        cell.charterProvider = CharterProviders.providers[indexPath.row]

        return cell
    }
}

Upvotes: 3

Views: 714

Answers (1)

TylerP
TylerP

Reputation: 9829

You are not keeping a strong reference to the ProviderTableDataSource that you create when you create your table view:

let providerTable = { () -> UITableView in
    let providerDataSource = ProviderTableDataSource()

    let table = UITableView()
    table.dataSource = providerDataSource
    table.translatesAutoresizingMaskIntoConstraints = false
    table.register(ProviderTableViewCell.self, forCellReuseIdentifier: "providerCell")
    return table
}()

UITableView's dataSource property is weak, so you can't rely on that to hold a strong reference to a ProviderTableDataSource. See the docs here: https://developer.apple.com/documentation/uikit/uitableview/1614955-datasource?changes=_6

What you want to do is probably something like this:

class ProviderViewController: UIViewController {
    private let providerDataSource = ProviderTableDataSource()

    private(set) lazy var providerTable: UITableView = {
        let table = UITableView()
        table.dataSource = self.providerDataSource
        table.translatesAutoresizingMaskIntoConstraints = false
        table.register(ProviderTableViewCell.self, forCellReuseIdentifier: "providerCell")
        return table
    }()

    // [...]
}

This way, the view controller is holding a strong reference to the ProviderTableDataSource so it will not be released after the creation of the table view.

Upvotes: 6

Related Questions