为什么我的iOS应用程序中的一个函数被调用两次?

时间:2018-09-29 07:20:20

标签: ios swift function

我做了我的第一个iOS应用。但是有两个我无法摆脱的烦人的错误。我希望有人能帮助我!

该应用程序应经过训练以读取乐谱。用户指定他的乐器和级别(在上一个视图控制器上),并基于此,在屏幕上以音乐符号形式放置随机音符。用户应在文本字段中匹配这些笔记,应用程序会跟踪分数并在十个正确答案后提高级别。

但是,以某种方式,我在生成随机笔记的功能上遇到了问题。由于某种原因,该函数被调用两次,第一次生成注释,将其保存在全局变量中,并创建带有注释的标签。第二次,它更改全局变量,但不更改标签。这次它返回以下错误消息:2018-09-29 23:08:37.279170+0200 MyProject[57733:4748212] Warning: Attempt to present <MyProject.ThirdViewController: 0x7fc709125890> on <MyProject.SecondViewController: 0x7fc70900fcd0> whose view is not in the window hierarchy! 因此,用户在屏幕上回答了问题,但应用程序认为这是错误的答案,因为它存储了第二个答案。

用户第二次回答问题时,该函数仅被调用一次,但是从文本字段中读取的内容不会更新为新值,而是与第一个问题相同。

下面是给出问题的代码:

import UIKit

class ThirdViewController: UIViewController
{

// snip

func setupLabels() {
    // snip
    // here the random notes are created, this is function is called multiple times for some reason
    let antwoord = Noten()
    let antwoordReturn = antwoord.generateNoten(instrument: instrument, ijkpunt: ijkpunt, aantalNoten: aantalNoten-1)
    let sleutel = antwoordReturn.0
    let heleOpgave = antwoordReturn.1
    print(heleOpgave)
    print(PassOpgave.shared.category)
    let heleOpgaveNummers = antwoordReturn.2
    // snip
    var a = 0
    while a < aantalNoten {
        // the labels are created, no problems there
        let myTekstveld = UITextField(frame: CGRect(x: labelX, y: labelY + 150, width: labelWidth, height: labelHeight / 2))
        myTekstveld.backgroundColor = UIColor.white
        myTekstveld.textAlignment = .center
        myTekstveld.placeholder = "?"
        myTekstveld.keyboardType = UIKeyboardType.default
        myTekstveld.borderStyle = UITextField.BorderStyle.line
        myTekstveld.autocorrectionType = .no
        myTekstveld.returnKeyType = UIReturnKeyType.done
        myTekstveld.textColor = UIColor.init(displayP3Red: CGFloat(96.0/255.0), green: CGFloat(35.0/255.0), blue: CGFloat(123.0/255.0), alpha: 1)
        myTekstveld.delegate = self as? UITextFieldDelegate
        myTekstveld.tag = a + 1
        view.addSubview(myTekstveld)

        a += 1
        labelX += labelWidth
    }

    // the button is created
}

override func viewDidLoad()
{
    super.viewDidLoad()
    // snip
    setupLabels()
}

@objc func buttonAction(sender: UIButton!) {
    // snip
    // here the text from the text fields is read, but this only works the first time the buttonAction is called, the next times, it simply returns the first user input.
    while a <= aantalNoten {
        if let theLabel = view.viewWithTag(a) as? UITextField {
            let tekstInput = theLabel.text!
            userInput.append(tekstInput)
        }
        a += 1
    }

    // snip 

    setupLabels()
    return
}

// snip

3 个答案:

答案 0 :(得分:2)

当您不打算这样做时,您有两个ThirdViewController实例。

此错误非常清楚:

2018-09-29 23:08:37.279170+0200 MyProject[57733:4748212] Warning: Attempt to present <MyProject.ThirdViewController: 0x7fc709125890> on <MyProject.SecondViewController: 0x7fc70900fcd0> whose view is not in the window hierarchy!

这是告诉您SecondViewController甚至不在屏幕上时正在尝试创建ThirdViewController。这表明错误出在SecondViewController中(可能在未显示屏幕时观察到通知或其他行为)。当然,您也可能有两个SecondViewController的实例。

我怀疑您是在尝试手动构建所有这些内容,而不是让Storyboards为您完成工作。很好,但是在这种情况下,这类错误更常见。进一步调试此错误的最佳方法是设置一些断点,并仔细检查对象的地址(例如0x7fc709125890)。您需要在要创建另一个的地方进行搜寻。

答案 1 :(得分:0)

您的 genreteNoten 方法被多次调用,因为它是从 setupLabels 调用的,而 setupLabels 又是从 viewDidLoad 调用的。

viewDidLoad 可能会被多次调用,您的代码应对此进行说明。就像this answer中提到的一个类似问题:

  

如果您的代码只需要为控制器运行一次,请使用-awakeFromNib。

答案 2 :(得分:0)

我自己设法部分地解决了我的第二个问题(从文本字段中读取的内容没有更新为第二个答案),方法是不再创建它们。 我向setupLabels函数添加了一些代码,以便仅在没有输入的情况下创建文本字段:

let myTekstveld = UITextField()
if (view.viewWithTag(a+1) as? UITextField) != nil {  
}
else {
myTekstveld.frame = CGRect(x: labelX, y: labelY + 100, width: labelWidth, height: labelHeight / 2)
// snip
myTekstveld.tag = a + 1
view.addSubview(myTekstveld)
}

该应用现在可以按预期运行,唯一的问题是每个问题后文本字段都不会清除。