我是iOS开发的新手,所以如果我缺少明显的东西,请原谅我。我有一个视图控制器,其中包含一个子视图,在该子视图中我创建了一个数字键盘,目前,我想为数字键盘视图提供自己的UIView子类,因为我想用它做一些不同的事情。现在,数字键盘只是根据按下的键创建一个字符串,并且我已经建立了一个委托将该字符串传递给其他任何我想使用它的地方(尽管我也尝试过直接在视图中访问原始输入控制器,让a = subview(); label.text = a.rawInput)。

每当我尝试将视图控制器中的UILabel文本设置为子视图的原始输入时,无论是通过委派还是直接将其设置为nil,都会在标题中引发错误。

我尝试过的事情:

  • 在viewDidLoad覆盖内部和外部设置文本
  • 在视图控制器内设置一个变量(testInput)以采用子视图的原始输入,并将标签文本设置为该变量(我已经确认视图控制器内的变量已正确设置,因此没有委派问题)
  • 在testInput变量上使用didSet既可以将标签文本设置为testInput,也可以尝试调用viewDidLoad并在那里设置标签文本(在didSet中打印testInput确实会打印正确的字符串FWIW)
  • 删除并重新链接我的标签
  • 的IBOutlet
  • IBOutlet变量
  • 的强存储和弱存储
  • 尝试在视图控制器内的另一个子视图中执行相同的操作,以防由于某种原因它是视图控制器自身的错误
  • 到处搜索适合
  • 的解决方案

    我很沮丧这是我相关的数字键盘代码:
    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)
    }
    

    这是视图控制器代码:
    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
    }
    

    附带说明一下,如果您发现我的协议不是类类型,出于某种原因,请在其中添加:class并将我的委托声明为弱变量,以防止委托起作用。有什么建议吗?

    最佳答案

    您像这样分配了代表:

    var delegate: NumpadDelegate? = BudgetViewController()
    

    那不引用呈现场景的视图控制器,而是引用一个新的空白视图控制器。这就是为什么当您使用weak时,为什么将其释放了(因为视图控制器的孤立实例对此没有强大的引用)。

    您应该再次将协议定义为class协议,并将delegate定义为:
    weak var delegate: NumpadDelegate?
    

    然后,在视图控制器的viewDidLoad中,取消注释设置该委托的行:
    numpadView.delegate = self
    

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

    这两个问题(即,获得要作为Numpad视图的委托的视图控制器的引用;获得对情节提要所呈现的Numpad视图的引用)都对演示情节提要场景的过程产生了一些误解。 。

    该过程基本上如下:
  • 使用您指定为该场景的基类的任何类实例化视图控制器;
  • 的根view以及该场景上的所有子视图都将为您实例化;
  • 情节提要
  • 情节提要将场景基类中的IBOutlet引用连接到您创建的出口。和
  • 调用视图控制器的viewDidLoad

  • 这太简单了,但这是基本过程。

    但关键是要为您创建所有在情节提要场景中引用的视图控制器和视图。您不想自己尝试创建其中的任何一个(并且()BudgetViewController()末尾的Numpad()表示“创建x的新实例”,这不是我们想要在此处进行的操作)。

    因此,当我们需要获取对视图控制器的引用以便可以以编程方式为其中一个视图指定delegate时,可以在viewDidLoad中进行此操作,此时self引用故事板为我们实例化的视图控制器。我们不想实例化一个新实例。同样,当您要引用情节提要为我们实例化的Numpad(以连接其delegate)时,请使用在Interface Builder中连接的IBOutlet,而不是通过Numpad编程地实例化一个新的Numpad()

    10-07 19:49