如何在两个单独的视图控制器上跟踪数组的元素?

Posted

技术标签:

【中文标题】如何在两个单独的视图控制器上跟踪数组的元素?【英文标题】:How do I keep track of elements of an array on two separate view controllers? 【发布时间】:2017-07-25 06:28:13 【问题描述】:

我正在开发一个测验应用程序,在第一个 UIViewController 上,用户被问了一个问题,并给出了四个按钮作为答案。如果他们得到正确的答案,则该元素将从要问的问题数组中删除。但是,如果我实现对另一个视图控制器的转场,当它转回第一个视图控制器以询问另一个问题时询问用户是否要继续,则数组将重新填充用户已经回答的问题,即使他们应该是删除。我如何确保一旦我从第二个视图控制器中切换到询问用户是否要继续的第二个视图控制器,问题数组不会重新填充已回答的问题?

这是我的代码:

import UIKit

class ViewController: UIViewController 

var questionList = [String]()

func updateCounter() 

    counter -= 1
    questionTimer.text = String(counter)

    if counter == 0 
        timer.invalidate()
        wrongSeg()
        counter = 15
    



func randomQuestion() 

    //random question
    if questionList.isEmpty 
        questionList = Array(QADictionary.keys)
        questionTimer.text = String(counter)

    

    let rand = Int(arc4random_uniform(UInt32(questionList.count)))
    questionLabel.text = questionList[rand]

    //matching answer values to go with question keys
    var choices = QADictionary[questionList[rand]]!

    questionList.remove(at: rand)


    //create button
    var button:UIButton = UIButton()

    //variables
    var x = 1
    rightAnswerBox = arc4random_uniform(4)+1

        for index in 1...4 

            button = view.viewWithTag(index) as! UIButton
            if (index == Int(rightAnswerBox))
                button.setTitle(choices[0], for: .normal)
            
            else 
                button.setTitle(choices[x], for: .normal)
                x += 1
            

            randomImage()
        
    


let QADictionary = ["Who is Thor's brother?" : ["Atum", "Loki", "Red Norvell", "Kevin Masterson"], "What is the name of Thor's hammer?" : ["Mjolinr", "Uru", "Stormbreaker", "Thundara"], "Who is the father of Thor?" : ["Odin", "Sif", "Heimdall", "Balder"]]

//wrong view segue
func wrongSeg() 
   performSegue(withIdentifier: "incorrectSeg", sender: self)


//proceed screen
func rightSeg() 
    performSegue(withIdentifier: "correctSeg", sender: self)

        //variables
var rightAnswerBox:UInt32 = 0
var index = 0

//Question Label
@IBOutlet weak var questionLabel: UILabel!

//Answer Button
@IBAction func buttonAction(_ sender: AnyObject) 

if (sender.tag == Int(rightAnswerBox) 
    //rightSeg()
    print ("Correct!")

    if counter != 0 
        counter = 15
        questionTimer.text = String(counter)
    
else if (sender.tag != Int(rightAnswerBox)) 
    wrongSeg()
print ("Wrong!")
    timer.invalidate()
    questionList = []

    
   randomQuestion()


override func viewDidAppear(_ animated: Bool) 
randomQuestion()


//variables
var counter = 15
var timer = Timer()
@IBOutlet weak var questionTimer: UILabel!

override func viewDidLoad() 
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    timer = Timer.scheduledTimer(timeInterval: 1, target:self, selector: #selector(ViewController.updateCounter), userInfo: nil, repeats: true)
        

第二个视图控制器的代码:

import UIKit

class ContinueScreen: UIViewController     
//correct answer label
@IBOutlet weak var correctLbl: UILabel!
//background photo
@IBOutlet weak var backgroundImage: UIImageView!

func backToQuiz() 
    performSegue(withIdentifier: "continueSeg", sender: self)


@IBAction func `continue`(_ sender: Any) 
    backToQuiz()


override func viewDidLoad() 
    super.viewDidLoad()

【问题讨论】:

使用一个对象来存储你的数据并从你的相关视图控制器中引用它的一个实例;另外,请确保 continueSegunwind segue 如何放松转场与常规转场不同? 可以搜索资料;苹果对它们有很好的技术说明。基本上,展开转场会回到现有的视图控制器实例 【参考方案1】:

您需要为此实现委托。您可以找到更多信息here。

您的问题与this有关。

请看一遍。希望有帮助。

【讨论】:

我认为问题不在于视图控制器之间来回传输数据,而是在backToQuiz中创建父视图控制器的新实例 我怎样才能阻止视图控制器的新实例? 不,为什么要创建新实例。请注意,在 Swift 中,数组是值类型。因此,默认情况下,如果您复制数组,则会创建一个新实例,并将所有元素复制到该实例中。无论您将做什么更改都将在新副本上完成,而不是传播到从中复制它的数组。 第二个视图控制器根本没有使用数组,所以它没有复制到任何地方。问题是在backToQuiz 中创建了一个新的视图控制器,而不是返回到第一个。 未创建新的视图控制器。您可以在控制台中检查。问题出在你的逻辑某处。我可以看到的一个地方是,对于每个错误的答案,您都将 questionsArray 设为空。它在 viewDidAppear 上再次重新填充数组。我不知道它是否有意。【参考方案2】:

问题是你——当你回到backToQuiz()中的第一个视图控制器时——调用performSegue,然后

创建第一个视图控制器的实例并 用原始(未修改的)测验数据重新初始化它

相反,您应该这样做

func backToQuiz()  
   if let nav = self.navigationController 
        nav.popViewController(animated: true)
     else 
        self.dismiss(animated: true, completion: nil)
    

返回父视图控制器实例。

【讨论】:

那么,在使用 segues 时确保不创建视图控制器的新实例的最佳方法是什么? 您的方式是弹出 ViewController / 关闭当前的 ViewController,如上所示,或者查看@Paulw11 在上面的评论中提到的 segue unwinding。 感谢您的洞察力!真的很有帮助..我实现了你的代码,它并没有完全符合我的要求,但我认为这是朝着正确方向迈出的一步。

以上是关于如何在两个单独的视图控制器上跟踪数组的元素?的主要内容,如果未能解决你的问题,请参考以下文章

在创建表格视图单元之前删除数组中的元素

使用两个继承类创建故事板屏幕

将 segued 数据存储在单独的视图控制器上(swift 4)

为两个不同的视图控制器和数组使用框架

如何使用来自另一个视图控制器swift的用户输入创建具有表视图单元格的列表

如何以编程方式为情节提要中的子视图设置视图控制器?