网点是零?

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() 
} 
} 

然后在 QuoteViewviewDidLoad 中设置标签的文本

override func viewDidLoad(){
    self.quoteTitle.text = self.quoteTitleString
    etc...
}

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

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

这里一个优雅的解决方案是在 QuoteView 中创建一个 "quote" 属性 并将其设置在 "prepareForSegue" 中。然后稍后使用该引号 属性 在 vi​​ewDidLoad 或 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()
}

从 "why it doesn't work" 关于尝试从视图控制器外部设置视图控制器的出口的问题稍微退后一步,我给你一个简单的规则:

"Don't do that."

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

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

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

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

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

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

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

@beyowulf 和@harshitgupta 提供了有关如何以正确方式进行操作的详细示例。 (尽管我认为将属性安装到 UI 中的代码应该在 viewWillAppear 中,而不是 viewDidLoad 中。这样,在显示视图控制器的情况下,被另一个更改其值的视图控制器覆盖,然后被覆盖, 它会在再次显示时更新屏幕上更改的值。)