Liam S
Liam S

Reputation: 43

Swift not allowing me to set variable data

I am trying to create a simple contact list app as an avenue of learning Swift. Unfortunately no matter what I try I cannot have my contacts' details display into an editable text field on a different view controller to the tableview (which contains the main contacts).

Here is the block of code that should be effecting the text fields (i am unsure of what other code to supply)

 override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "showDetail" {
        if let indexPath = self.tableView.indexPathForSelectedRow {
            let object = objects[indexPath.row]
            let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
            print(object.firstName)
            controller.fiName?.text = object.firstName
            controller.laName?.text = object.lastName
            controller.miName?.text = object.middleName
            controller.aess?.text = object.address
            controller.phoNumber?.text = object.phoneNumber
            controller.yearBirth?.text = String(object.age)
            print(controller.fiName)
            controller.detailItem = object
            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
            controller.navigationItem.leftItemsSupplementBackButton = true
        }
    }

The result of the first print line is as I expect it to be, which is the name of the contact, but the program crashes on the second print, with an 'EXC_BAD_INSTRUCTION' / fatal error: unexpectedly found nil while unwrapping and optional value.

Why can I not set the controller.fiName?.text? Thank you in advance for any help.

Upvotes: 0

Views: 131

Answers (3)

Joe Benton
Joe Benton

Reputation: 3753

You are setting the fiName label text too early, where the label hasn't been allocated yet. Instead pass through the object and then set the text in viewDidLoad of the next controller.

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "showDetail" {
        if let indexPath = self.tableView.indexPathForSelectedRow {
        let object = objects[indexPath.row]
        let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController

        //pass through object:
        controller.object = object

        print(object)
    }
}

And then in the next viewController viewDidLoad set the text:

override viewDidLoad() {
    //Now set the text value here:
    fiName?.text = object.firstName
}

Upvotes: 2

ale_stro
ale_stro

Reputation: 816

Just object should be passed in prepareForSegue

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "showDetail" {
            if let indexPath = self.tableView.indexPathForSelectedRow {
                let object = objects[indexPath.row]
                let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
                controller.detailItem = object
                controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
                controller.navigationItem.leftItemsSupplementBackButton = true
            }
        }
    }

And then outlets should be setup in viewDidLoad

class DetailViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        fiName?.text = detailItem.firstName
        laName?.text = detailItem.lastName
        miName?.text = detailItem.middleName
        aess?.text = detailItem.address
        phoNumber?.text = detailItem.phoneNumber
        yearBirth?.text = String(detailItem.age)
    }
}

Upvotes: 1

Dejan Skledar
Dejan Skledar

Reputation: 11435

I guess your filName is an UILabel or UITextField right?

If you check your code in DetailViewController you will notice this line:

@IBOutlet weak var filName: UITextField!

You see the ! at the end of the line?

This means, that the variable (aka outlet) filName cannot be set at the initialization, but will be set at some point later.

Now, what you do is you init your class, and try to access that property that is not yet set at the initialization.

To get around this, create an object instance in DetailViewController, and set that instance to the selected object, and then set the label properties in the viewDidLoad function.

Something like this:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "showDetail" {
        if let indexPath = self.tableView.indexPathForSelectedRow {
            let object = objects[indexPath.row]
            let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
            controller.object = object
        }
}

And then in the viewDidLoad of DetailViewController:

override viewDidLoad() {
       fiName?.text = object.firstName
       laName?.text = object.lastName
       miName?.text = object.middleName
       aess?.text = object.address
       phoNumber?.text = object.phoneNumber
       yearBirth?.text = String(object.age)
       navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
       navigationItem.leftItemsSupplementBackButton = true
}

Upvotes: 2

Related Questions