Camillo
Camillo

Reputation: 544

Swift: Update UITableView.cell.textLabel.text from other class

I have a UITableViewController:

class MyMenuTableViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()        
    }

    func updateFirstMenuRow() {
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                println("tableview is \(self.tableView)")
                var indexPath = NSIndexPath(forRow: 0, inSection: 0)
                var cell = self.tableView.cellForRowAtIndexPath(indexPath)
                var rand = arc4random()
                cell!.textLabel!.text = "\(rand)"
                cell!.setNeedsLayout()
                cell!.setNeedsDisplay()
                println("cell is \(cell)")
                println("rand is \(rand)")
                println("textLabel.text is \(cell!.textLabel!.text!)")
            })
    }

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // Return the number of sections.
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // Return the number of rows in the section.
        return 3
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        var cell = tableView.dequeueReusableCellWithIdentifier("CELL") as? UITableViewCell

            if (cell == nil) {
                cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "CELL")
            }

            switch indexPath.row {
            case 0:
                cell!.textLabel?.text = "This is the old text"
            case 1:
                cell!.textLabel?.text = "Foo"
            case 2:
                cell!.textLabel?.text = "Bar"
            default:
                cell!.textLabel?.text = "UNDEFINED"
            }

        return cell!

    }

}

Note that I have a function updateFirstMenuRow() where I'll update the textLabel.text of the first tableView row with a different value (in my text case, a different number).

I need to run updateFirstMenuRow() from another class, like below:

class MyOtherClass:UIViewController{

    override func viewDidLoad() {
        super.viewDidLoad()
        MyMenuTableViewController().updateFirstMenuRow()
    }
    //.....
}

It will show all println in the console, however it does not update the the cell.textLabel.text with a random number.

In console, I can see that:

However, the actual textLabel.text in the MyMenuTableViewController is never updated, and stays at it's initial value, "This is the old text".

When I try to run updateFirstMenuRow() within UITableViewController, it will work - meaning, it will update the textLabel.text of the first row in the tableView:

class MyMenuTableViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate {

    override func viewDidAppear(animated: Bool) {
        updateFirstMenuRow()
    }

}

Note that I'm trying to run the update functions from the main thread, as suggested by other stackoverflow questions. However, no success.

I have been struggling with this for several hours now, I'd be glad if anyone can give me some pointers as for why my update function will not properly run - my guess is that it doesn't have "write access" to the tableView in MyMenuTableViewController. Thanks a lot in advance!

Upvotes: 1

Views: 1351

Answers (2)

Camillo
Camillo

Reputation: 544

I managed to solve my problem thanks to Paul's answer.

I am in fact using a delegate, which is triggered in the MyOtherClass, to "forward" the command to update the textLabel.text - however, I managed to get the correct reference.

Before, I was using MyMenuTableViewController() twice

Now I am using var menuTableViewController:MyMenuTableViewController?, then I set the value once with self.menuTableViewController = MyMenuTableViewController() and then subsequently I use menuTableViewController! or menuTableViewController!.updateFirstMenuRow(), so I always update the tableView in the "same" instance of MyMenuTableViewController.

Upvotes: 0

Paulw11
Paulw11

Reputation: 114865

This

MyMenuTableViewController().updateFirstMenuRow()

creates a new instance of MyMenuTableViewController - so the method is executed on an instance that isn't on screen. This is why you see the output of the println but no change in the tableview.

You need to pass a reference to the MyMenuTableViewController instance to the MyOtherClass instance. You need to add a property to MyOtherClass to hold the reference -

menuTableViewController:MyMenuTableViewController?

You don't show how you get from one to the other, but, for example if it was via a segue you would use the following -

override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!)  {
    if (segue.identifier == "someIdentifier") {
        let destinationVC = segue.destinationViewController as MyOtherClass
        destinationVC.menuTableViewController = self
    }
}

Then in your MyOtherClass you can say -

if (self.menuTableViewController != nil) {
    self.menuTableViewController!.updateFirstMenuRow()
}

Upvotes: 1

Related Questions