【问题标题】:Outlets are nil?奥特莱斯是零?
【发布时间】:2016-05-06 21:30:26
【问题描述】:

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

【问题讨论】:

  • 你试图在什么方法里面修改这些标签?
  • 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() } }
  • 就这样吧,beyowulf 是对的——还没有设置网点。
  • 听说过数据模型吗?

标签: ios swift uistoryboardsegue


【解决方案1】:

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...
}

【讨论】:

    【解决方案2】:

    从关于尝试从视图控制器外部设置视图控制器的出口的“为什么它不起作用”问题退后一点,我给你一个统一的规则:

    “不要那样做。”

    您应该将另一个视图控制器的出口视为私有的,而不是试图操纵它们。这违反了封装原则,违反了面向对象设计的重要思想。

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

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

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

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

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

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

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

    【讨论】:

    • 解释得很好。特别提到了相关的OO机制。也同意 viewWillAppear 方案。一个人可以做出深思熟虑的决定。根据用例将代码放在哪里。
    【解决方案3】:

    发生这种情况是因为通常 UI(视图)元素在调用 viewDidLoad 之前还没有准备好进行操作。

    这里一个优雅的解决方案是在 QuoteView 中创建一个“quote”属性并将其设置在“prepareForSegue”中。然后稍后使用该引用属性在 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)!];
      } 
    } 
    

    然后在报价视图中

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

    【讨论】:

    • 我喜欢您关于使用自定义引用对象并将该对象传递给目标视图控制器的建议。 (已投票。)我建议编辑您的答案,将值安装到 viewWillAppear 的文本字段中,而不是“viewDidLoad”(如我的回答中所述)
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 2018-12-22
      • 2020-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-28
      相关资源
      最近更新 更多