9

i'm quite new to this. I've spent some hours to go through the various questions on this topic but couldn't find an answer that fits to me question.

I have an viewcontroller (not a tableviewcontroller) with a tableview as subview. My question is how to reload the table data inside the :viewwillappear method of the view controller. Inside the method i can't "access" the tableview instance. (Also i understand i can't use reloaddata() because im not using a tableviewcontroller).

Do you know any simple solution? (i very much assume that a protocol could help here?)

this is the code in short:

class ViewController3: UIViewController, UITableViewDataSource, UITableViewDelegate {

    var Person_data = [Person]()

    override func viewDidLoad() {
        super.viewDidLoad()

        let tb: UITableView = UITableView(frame: CGRect(x: 10, y: 50, width: 200, height:600), style: UITableViewStyle.Plain)

        tb.dataSource = self
        tb.delegate = self
        super.view.addSubview(tb)

        fetch_data()
    }


        func tableView(tableview: UITableView, numberOfRowsInSection section: Int) -> Int {
            let rows = Person_data.count
            return rows
        }


       func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
        {  
            let cell: UITableViewCell = UITableViewCell()
            cell.textLabel?.text = Person_data[indexPath.row].name
            return cell
        }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        fetch_data()      
      // reload at this point

    } 


    func fetch_data() {

       let tb_fetchRequest = NSFetchRequest(entityName: "Person")
        do {

            let tb_fetchResults = try my_moc.executeFetchRequest(tb_fetchRequest) as? [Person]
            Person_data = tb_fetchResults!
        } catch let error as NSError {
                print("request error: \(error)")
            }

        }
    }
Netzer
  • 227
  • 1
  • 3
  • 8

5 Answers5

8

Your problem is that tb is a local variable, so it is not visible outside of viewDidLoad().

If you make tb a property (a.k.a. instance variable) of your view controller, then you can use it from any of the controller’s methods:

class ViewController3: UIViewController, UITableViewDataSource, UITableViewDelegate {

    var Person_data = [Person]()

    private var tb: UITableView?  // Now the scope of tb is all of ViewController3...

    override func viewDidLoad() {
        super.viewDidLoad()

        // ...so it is visible here...

        tb = UITableView(frame: CGRect(x: 10, y: 50, width: 200, height:600), style: UITableViewStyle.Plain)

        ...
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        fetch_data()      

        tb?.reloadData()   // ...and it is also visible here.
    } 

Note that in your code, the fact that tb is a local variable doesn’t mean that your UITableView object disappears when viewDidLoad() finishes. It means that your reference to the UITableView disappears. The table view object itself lives on because it is added to your view hierarchy, but you don’t have a reference to it anymore because your variable went out of scope.

For further reading on the distinction between variables and the objects they reference, search for “scope” and “pass by reference.”

Paul Cantrell
  • 9,175
  • 2
  • 40
  • 48
  • Thanks for the hint. I Took a deeper look at instance variables – Netzer Oct 29 '15 at 22:15
  • Also take a look at @Arsen’s answer, which shows how you can prevent tableView from being an optional be initializing it immediately. That technique often does not work with UI elements, but it does work in this case. – Paul Cantrell Oct 30 '15 at 00:05
  • Thank you from Swift 4 in 2019! – Sylar Jan 15 '19 at 05:34
2

You can access your tableView IBOutlet in viewWillAppear:, you can also call reloadData. I'm not sure why you think you can't, but it should work fine.

Charles A.
  • 10,685
  • 1
  • 42
  • 39
1

You have to create a variable with link to tableView and create it before viewWillAppear.

class ViewController3: UIViewController, UITableViewDataSource, UITableViewDelegate {
    private let tableView = UITableView(frame: CGRect(x: 10, y: 50, width: 200, height:600), style: UITableViewStyle.Plain)
    var Person_data = [Person]()

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.dataSource = self
        tableView.delegate = self
        super.view.addSubview(tb)

        fetch_data()
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        fetch_data()      
        tableView.reloadData()
    } 
}
Forge
  • 6,538
  • 6
  • 44
  • 64
Arsen
  • 10,815
  • 2
  • 34
  • 46
1

I'm just adding my answer with the other answer here. Rather than reloading the whole tableView you should do the following:

When some new item/data has been added to the data source we usually do

tableView.reloadData() // DON'T DO IT

I would share a better way of optimizing this process. Rather do as below when some new data/item has been appended to the data you need to show:

 // Calculate the latest row to load, asuming 'items' is the array where new data is appended
 let index = self.items.count - 1

 // Calculate the indexPath
 let indexPath = IndexPath(item: index, section: 0)

 // Insert the latest row only
 self.tableView.insertRows(at: [indexPath], with: .automatic)

 // scroll to the last item
 self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)

If no new data is added to the items/data list but one of your existing item/data has been updated then just do as follows instead of loading the whole tableView.

tableView.reloadRows(at: [indexPath], with: .automatic)
0
class ViewController3: UIViewController, UITableViewDataSource, UITableViewDelegate {
    private let tableView = UITableView(frame: CGRect(x: 10, y: 50, width: 200, height:600), style: UITableViewStyle.Plain)
    var Person_data = [Person]()

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.dataSource = self
        tableView.delegate = self
        super.view.addSubview(tb)

        fetch_data()
    }



    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        fetch_data()      
        tableView.reloadData()

    } 
    }
Arsen
  • 10,815
  • 2
  • 34
  • 46