[英]Outlets are nil?
我在故事板中为标签创建(并链接)了一些出口,当我尝试修改文本时,我的应用程序会抛出异常并冻结,因为它们显然是nil
。
码:
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!
}
我试图在前一个视图控制器的prepareForSegue
方法中设置它们,如下所示:
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()
}
}
在prepareForSegue
您的出口尚未初始化,因此您无法设置它们的属性。 你应该创建String属性并设置它们,或者更好,只需传递你的quote
对象。 例如:
overide func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "indivQuoteSegue") {
let svc = segue.destinationViewController as! QuoteView
let quote = quoteArray[(tableView.indexPathForSelectedRow?.row)!];
svc.quoteTitleString = quote.getQuoteTitle()
svc.quoteAuthorString = quote.getQuoteAuthor()
svc.quoteContentString = quote.getQuoteContent()
svc.quoteCategoryString = quote.getCategory()
svc.quoteTimestampString = quote.getQuoteTimestamp()
}
}
然后在QuoteView
的viewDidLoad
中设置标签的文本
override func viewDidLoad(){
self.quoteTitle.text = self.quoteTitleString
etc...
}
它的发生是因为通常UI(视图)元素在调用viewDidLoad之前还没有准备好进行操作。
这里一个优雅的解决方案是在QuoteView中创建一个“quote”属性并将其设置为“prepareForSegue”。 然后使用该quote属性在viewDidLoad或viewWillAppear方法中加载UI元素。 有关详细信息,请参阅@Duncan C的答案。
overide func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "indivQuoteSegue") {
let svc = segue.destinationViewController as! QuoteView
svc.quote = quoteArray[(tableView.indexPathForSelectedRow?.row)!];
}
}
然后在QuoteView中
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated);
self.quoteTitle.text = self.quote.getQuoteTitle()
self.quoteAuthor.text = self.quote.getQuoteAuthor()
self.quoteContent.text = self.quote.getQuoteContent()
self.quoteCategory.text = self.quote.getCategory()
self.quoteTimestamp.text = self.quote.getQuoteTimestamp()
}
稍微退一步“为什么它不起作用”的问题试图从视图控制器外部设置视图控制器的出口,我给你一个平坦的规则:
“不要这样做。”
您应该将另一个视图控制器出口视为私有,而不是试图操纵它们。 这违反了封装原则,也是OO设计中的重要思想。
想象一下:我有一个立体声设备的控制面板对象。 控制面板上有一堆控制UI对象,可以让用户设置均衡,降噪等。然后它有一个公共API,用于与系统的其他软件组件连接。
如果其他对象进入我的控制面板并执行诸如更改均衡滑块的值之类的操作,那么我以后就无法返回并将均衡器的UI元素替换为使用拨号,数字输入或其他一些UI元素,没有打破应用程序的其余部分。 我已将程序中的其他对象紧密耦合到应该是我的控制面板对象的私有实现的一部分。
在您的情况下,它是平面不起作用,因为在prepareForSegue中尚未加载目标视图控制器的视图。
即使在它可以工作的情况下,你仍然不应该这样做。
相反,您应该创建视图控制器的公共属性,让外部对象指定设置的值。 然后视图控制器的viewWillAppear方法应该将这些属性中的值应用于UI。
当您这样做时,如果您稍后对UI进行更改,您所要做的就是确保公共属性仍然按预期工作。
@beyowulf和@harshitgupta详细介绍了如何以正确的方式做到这一点。 (虽然我认为将属性安装到UI中的代码应该在viewWillAppear中,而不是viewDidLoad。这样,如果显示视图控制器,由另一个更改其值的视图控制器覆盖,然后被覆盖,它会更新再次显示时,屏幕上的值会更改。)
您不能在segue中分配它们,因为它们尚未初始化,您可能会考虑使用可选绑定但它也不会起作用,解决方案是将您的数据结构或类作为var传递给segued视图然后更新将它放在viewDidLoad()中的新ViewController中或使用didSet {}。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.