奥特莱斯是零?

时间:2016-05-06 21:30:27

标签: ios swift uistoryboardsegue

我已经在故事板中为标签创建(并链接)了一些出口,当我尝试修改文本时,我的应用程序抛出异常并冻结,因为它们显然是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() 
    } 
} 

4 个答案:

答案 0 :(得分:6)

vmin中,您的商店尚未初始化,因此您无法设置它们的属性。您应该创建String属性并设置它们,或者更好,只需传递prepareForSegue对象。例如:

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() } } viewDidLoad设置标签'文字

QuoteView

答案 1 :(得分:2)

它的发生是因为通常在调用viewDidLoad之前,UI(视图)元素还没有准备好被操作。

这里优雅的解决方案是在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()
}

答案 2 :(得分:2)

从“为什么它不起作用”的问题稍微退一步试图从视图控制器外部设置视图控制器的插座,我给你一个平坦的规则:

“不要那样做。”

您应该将另一个视图控制器插座视为私有,而不是试图操纵它们。这违反了封装原则,也是OO设计中的重要思想。

想象一下:我有一个立体声设备的控制面板对象。控制面板上有一堆控制UI对象,可以让用户设置均衡,降噪等。然后它有一个公共API,用于与系统的其他软件组件连接。

如果其他对象进入我的控制面板并执行诸如更改均衡滑块的值之类的操作,那么我以后就无法返回并将均衡器的UI元素替换为使用拨号,数字输入或其他UI元素,不会破坏应用程序的其余部分。我已将程序中的其他对象紧密耦合到应该是我的控制面板对象的私有实现的一部分。

在你的情况下,它是不行的,因为在prepareForSegue中,目标视图控制器的视图尚未加载。

即使在可行的情况下,你仍然不应该这样做。

相反,您应该创建视图控制器的公共属性,让外部对象指定设置的值。然后视图控制器的viewWillAppear方法应该将这些属性中的值应用于UI。

当您这样做时,如果您稍后对UI进行更改,您所要做的就是确保公共属性仍然按预期工作。

@beyowulf和@harshitgupta详细介绍了如何以正确的方式做到这一点。 (虽然我认为将属性安装到UI中的代码应该在viewWillAppear中,而不是viewDidLoad。这样,如果显示视图控制器,由另一个更改其值的视图控制器覆盖,然后被覆盖,它会更新当再次显示时,屏幕上的值会更改。)

答案 3 :(得分:1)

你不能在segue中分配它们,因为它们尚未初始化,你可能会考虑使用可选绑定但它也不会起作用,解决方案是将你的数据结构或类作为var传递给segued视图然后在viewDidLoad()或使用didSet {}更新新ViewController中的出口。