Label not updating

Hi, I’m new to coding, and am attempting to build a to-do list app. I have created a table view, and in the cell, there is an accessory button. In the view controller, I wrote:
‘’’
func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
let mdvc = storyboard?.instantiateViewController(identifier: “MoreDetailController”) as? MoreDetailController

    print(mdvc!.titleLabel?.text) //prints nil

    mdvc?.titleLabel?.text = tasks[indexPath.row].name
    print(tasks[indexPath.row].name) //prints correct name        
    print(mdvc!.titleLabel?.text) //prints nil
    
    self.navigationController?.pushViewController(mdvc!, animated: true)
}

‘’’
In this code, it changes the view controller (this is successful when I run the app), yet the value of mdvc!.titleLabel?.text stays nil, even though tasks[indexPath.row].name is not nil (I printed this to make sure). To be clear, when this code runs, the page changes, the label on the new page does not. The code prints: nil, “Name of Task”, nil. For more clarification: in the new view controller called MoreDetailController,
‘’’
@IBOutlet weak var titleLabel: UILabel!
‘’’

I think the issue is to do with optional chaining but I can’t get it right, can someone please help me get the label text to become the tasks[indexPath.row].name? Thanks!

Are you using the built it label and accessoryview of the uitableviewcell or did you customize one in the storyboard?

I think I am using the built-in label of the uitabeviewcell: it is a little i with a circle on it. I declared it in the func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

cell.accessoryType = .detailDisclosureButton

return cell
}

usually if you use built-in labels its like this

for the normal label you have
[cell].textLabel!.text = “”

for the detail label you have
[cell].detailTextLabel!.text = “”

if the imageview you have
[cell].imageView!.image = [add UIImage here]

for the accessoryView you have
[cell].accessoryView = [add a view, usually its another UIImage]

ideally you don’t want to put a button as an accessoryview unless its like a checkbox or something

Hi, I think you’re understanding me wrong. My problem is that the label on the new UIViewController: MoreDetailController is not being updated when the accessory button is pressed. The button as an accessory view is working fine since the app is changing view controllers when it is tapped. However, the value of (mdvc!.titleLabel?.text) stays nil even though I assign it the value of (tasks[indexPath.row].name). I personally think it has something to do with optional chaining, but I don’t know how to fix that.

ah i see you need to use a segue and override the prepare method like this

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // Detect the indexpath the user selected

    let indexPath = tableView.indexPathForSelectedRow

    guard indexPath != nil else {
     // The user hasn't selected anything
         return
     }
         
    
    //load user information
    
    // Get the item the user tapped on
    let userSelected = self.users[indexPath!.row].profile
         
    // Get a reference to the detail view controller
    let detailVC = segue.destination as! DetailViewController
    
    
    // Pass the user profile to the detail view controller
    detailVC.listIndex = indexPath!.row
    detailVC.userProfile = userSelected
    
}

so userProfile and listIndex that was set was a variable of the other UIViewController called DetailViewController

you can then use the values passed to set labels or datasources using the viewDidLoad of the DetailViewController

Hi yes, thank you, that looks like it should work. However, I’m really new to coding, so where do I put this code? When I put it in my view controller it gives me the error message:

Method does not override any method from its superclass

this should be on your original viewcontroller, you also need to set the segue in the storyboard as well

the segue should be when an item is selected from the tableview it will then open the detailviewcontroller

if you have access to our paid course, at module 6 (the news app) you will be able to see a sample of this segue use and how to set it up

Hi Annique,

It looks like your initial code in your first post was intended to instantiate your MoreDetailController programatically rather than using a segue.

ie:

let mdvc = storyboard?.instantiateViewController(identifier: “MoreDetailController”) as? MoreDetailController
mdvc?.titleLabel?.text = tasks[indexPath.row].name
self.navigationController?.pushViewController(mdvc!, animated: true)

If that is the case then I assume that you would have embedded your calling ViewController in a NavigationController and then created your MoreDetailController in which you have your label (titleLabel).

In your storyboard you would have given your MoreDetailController a Storyboard ID in the Identity Inspector and named it MoreDetailController. Does that sound about right?

The correct way to pass data into your MoreDetailController is to declare a property in your MoreDetailController to accept the title name you are attempting to pass in. Make it something like:
var passedName: String? which will be an Optional.

Then in your calling ViewController you can say:

let mdvc = storyboard?.instantiateViewController(identifier: “MoreDetailController”) as! MoreDetailController
mdvc.passedName = tasks[indexPath.row].name
self.navigationController?.pushViewController(mdvc!, animated: true)

Note the as! MoreDetailController. It’s safe to do this because you know that it exists.

then in viewDidLoad() in your MoreDetailController unwrap the Optional like this:

if let text = passedName {
    titleLabel.text = text
}

It’s generally not a good idea to access an IBOutlet - titleLabel.text - in the way that you are attempting to do so. It’s more acceptable to pass in a value to variable declared as an Optional and then assign that to the label.text.

If you were to have force unwrapped the label and text like this:
mdvc?.titleLabel!.text! = tasks[indexPath.row].name

It would have worked.

1 Like

Thank you so much Chris! This explanation makes a lot of sense and my app now runs as I wanted it to!

1 Like

as a side note, what i said is basically the same thing but only programmatically, so you have 2 options :slight_smile:

1 Like