草庐IT

ios - Swift 2.2 - 更新 UILabel 抛出 "unexpectedly found nil while unwrapping an optional value"

coder 2023-09-15 原文

我是 iOS 开发的新手,所以如果我遗漏了一些明显的东西,请原谅我。我有一个 View Controller ,其中包含一个 subview ,我在其中创建了一个小键盘,目前我想为小键盘 View 提供它自己的 UIView 子类,因为我想用它做一些不同的事情。现在小键盘只是从按下的键创建一个字符串,我已经设置了一个委托(delegate)来将该字符串传递到我想使用它的任何其他地方(尽管我也尝试过直接在 View 中访问原始输入带有 let a = subview(); label.text = a.rawInput 的 Controller )。

每当我尝试将 View Controller 中的 UILabel 文本设置为 subview 的原始输入时,无论是通过委托(delegate)还是直接,都会发现 UILabel 为 nil 并在标题中抛出错误。

我尝试过的事情:

  • 在 viewDidLoad 覆盖内部和外部设置文本
  • 在 View Controller 中设置一个变量 (testInput) 以采用 subview 的原始输入并将标签文本设置为该变量(我已确认 View Controller 中的变量已正确设置,因此没有委派问题)
  • 在 testInput 变量上使用 didSet 将标签文本设置为 testInput 并尝试调用 viewDidLoad 并在其中设置标签文本(在此 didSet 中打印 testInput 确实打印出正确的字符串,FWIW)
  • 为我的标签删除和重新链接 IBOutlet
  • IBOutlet 变量的强弱存储
  • 尝试在 View Controller 中的另一个 subview 中做同样的事情,以防由于某种原因这是 View Controller 自己的错误
  • 到处寻找可行的解决方案

我被难住了。这是我相关的小键盘代码:

import UIKit

protocol NumpadDelegate {
func updateInput(input: String)
}

class Numpad: UIView {

// MARK: UI outlets
@IBOutlet weak var decButton: UIButton!


// MARK: Properties
var rawInput: String = ""
var visibleInput: String = ""
var calcInput: String = ""
var operandReady = 1
var percentWatcher = 0

var delegate: NumpadDelegate? = BudgetViewController()



// MARK: Functions
func handleRawInput(str: String) {
    rawInput += str
    print("numpad input is \(rawInput)")

    delegate?.updateInput(rawInput)
}

这是 View Controller 代码:

import UIKit

class BudgetViewController: UIViewController, NumpadDelegate {

// MARK: Properties
//@IBOutlet weak var transactionValueField: UITextField!
@IBOutlet weak var remainingCashForIntervalLabel: UILabel!
@IBOutlet weak var intervalDenoterLabel: UILabel!
@IBOutlet weak var currencyDenoterLabel: UILabel!
@IBOutlet weak var mainDisplayView: TransactionType!
@IBOutlet weak var inactiveInputView: InactiveInput!
@IBOutlet weak var numpadView: Numpad!
@IBOutlet weak var rawInputLabel: UILabel!


var remainingCashForInterval = 40

let display = TransactionType()
var testInput = "" {
    didSet {
        viewDidLoad()
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
//        let numpad = Numpad()
//        numpad.delegate = self
//        print("\(numpad.delegate)")
    self.rawInputLabel.text = testInput


}

func updateInput(input: String) {
    print("view controller now has \(input)")
    display.mainInput = input
    testInput = input
}

作为旁注,如果您注意到我的协议(protocol)不是类类型,出于某种原因向它添加 : class 并将我的委托(delegate)声明为弱变量会阻止委托(delegate)工作。有什么建议吗?

最佳答案

您像这样分配委托(delegate):

var delegate: NumpadDelegate? = BudgetViewController()

这并没有引用呈现场景的 View Controller ,而是一个新的空白 View Controller 。这就是为什么当你使用 weak ,它被释放的原因(因为 View Controller 的孤立实例没有对它的强引用)。

您应该将协议(protocol)定义为 class协议(protocol),并定义 delegate成为:

weak var delegate: NumpadDelegate?

然后,在 View Controller 的 viewDidLoad 中,取消注释设置该委托(delegate)的行:

numpadView.delegate = self

但是,不要取消注释 numpad = Numpad() 行;这是不正确的,因为它会创建另一个 Numpad实例。但是您确实想设置现有 Numpad 的委托(delegate), 不过。


这两个问题(即,获取对将成为 Numpad View 委托(delegate)的 View Controller 的引用;以及获取对 Storyboard呈现的 Numpad View 的引用)表明对呈现 Storyboard场景的过程。

基本流程如下:

  • View Controller 已实例化,使用您指定的任何类作为该场景的基类;
  • 它的根view ,以及该场景的所有 subview 都将为您实例化;
  • Storyboard将连接 IBOutlet场景基类中对您创建的 socket 的引用;和
  • View Controller 的 viewDidLoad被称为。

这过于简单化了,但这是基本过程。

但关键是 Storyboard场景中引用的所有这些 View Controller 和 View 都是为您创建的。您不想尝试自己创建任何这些(并且 ()BudgetViewController() 末尾的 Numpad() 表示“创建 x 的新实例”,这不是我们想要在这里做的)。

因此,当我们需要获取对 View Controller 的引用时,我们可以通过编程方式指定 delegate对于其中一个 View ,您可以在 viewDidLoad 中执行此操作,此时self引用 Storyboard为我们实例化的 View Controller 。我们不想实例化一个新的。同样,当您想要引用 Numpad 时 Storyboard为我们实例化(为了连接它的 delegate ),您使用 IBOutlet您连接到 Interface Builder,而不是以编程方式实例化一个新的 NumpadNumpad() .

关于ios - Swift 2.2 - 更新 UILabel 抛出 "unexpectedly found nil while unwrapping an optional value",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38554768/

有关ios - Swift 2.2 - 更新 UILabel 抛出 "unexpectedly found nil while unwrapping an optional value"的更多相关文章

随机推荐