I've created (and linked) some outlets to labels in my storyboard, and when I attempt to modify the text, my application throws an exception and freezes, because they are apparently nil
.
Code:
import UIKit
class QuoteView : UITableViewController {
@IBOutlet var quoteCategory: UILabel!
@IBOutlet var quoteTitle: UILabel!
@IBOutlet var quoteAuthor: UILabel!
@IBOutlet var quoteContent: UILabel!
@IBOutlet var quoteTimestamp: UILabel!
}
I'm attempting to set them in the prepareForSegue
method of previous view controller, like so:
overide func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "indivQuoteSegue") {
let svc = segue.destinationViewController as! QuoteView
let quote = quoteArray[(tableView.indexPathForSelectedRow?.row)!];
svc.quoteTitle.text = quote.getQuoteTitle()
svc.quoteAuthor.text = quote.getQuoteAuthor()
svc.quoteContent.text = quote.getQuoteContent()
svc.quoteCategory.text = quote.getCategory()
svc.quoteTimestamp.text = quote.getQuoteTimestamp()
}
}
Stepping back a little from the "why it doesn't work" question about trying to set a view controller's outlets from outside the view controller, I give you a flat rule:
"Don't do that."
You should treat another view controllers outlets as private and not try to manipulate them. That violates the principle of encapsulation, and important idea in OO design.
Imagine this: I have a control panel object for a piece of stereo equipment. The control panel has a bunch of control UI objects on it that let the user set equalization, noise reduction, etc. Then it has a public API that it uses to interface with the other software components of the system.
If other other objects reach into my control panel and do things like change the value of the equalization sliders, then I can't go back later and replace the UI elements for equalizers to use dials, or numeric inputs, or some other UI element, without breaking the rest of the app. I have tightly coupled other objects in my program to things that should be part of the private implementation of my control panel object.
In your case, it flat doesn't work because in prepareForSegue the destination view controller's views haven't yet been loaded.
Even in cases where it would work, you still should not do that.
Instead, you should create public properties of your view controller that let an outside object specify values for settings. Then the view controller's viewWillAppear method should apply the values in those properties to the UI.
When you do it that way, if you later make changes to the UI, all you have to do is to make sure the public properties still work as expected.
@beyowulf and @harshitgupta gave detailed examples of how to do it the right way. (Although I would argue that the code to install the properties into the UI should in viewWillAppear, not viewDidLoad. That way, in cases where a view controller is shown, covered by another view controller that changes its values, then uncovered, it updates the changed values on-screen when it gets shown again.)