向前传递后如何将数据向后传递给视图控制器?
Posted
技术标签:
【中文标题】向前传递后如何将数据向后传递给视图控制器?【英文标题】:How to pass data backwards to a view controller after passing forward? 【发布时间】:2017-07-25 19:06:15 【问题描述】:我正在开发一个测验应用程序,在要求您回答问题的初始视图控制器之后出现了第二个视图控制器。在第二个视图控制器上,用户必须按下一个按钮才能返回到初始视图控制器以被问到另一个问题。但是,当我从第二个视图控制器返回时,我相信正在创建初始视图控制器的新实例,并且会向用户询问他们已经回答的问题。我的初始视图控制器的 swift 文件中的代码是这样构造的,当用户被问到一个问题时,一旦该问题通过它的索引从数组中删除。我怎样才能使它的初始视图控制器的新实例不是通过从第二个视图控制器进行 segue 而创建的?或者有没有办法第二个视图控制器可以访问与初始视图控制器相同的方法?
这是我的初始视图控制器代码:
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()
if let nav = self.navigationController
nav.popViewController(animated: true)
else
self.dismiss(animated: true, completion: nil)
@IBAction func `continue`(_ sender: Any)
backToQuiz()
【问题讨论】:
【参考方案1】:先生,您需要的是代表或放松的继续。我更喜欢委托,因为它们更容易理解,而且我认为更强大。
在您的 ContinueScreen 视图控制器中定义类似于此的协议:
protocol QuizCompletedDelegate
func completedQuiz()
func canceledQuiz()
同样在您的 ContinueScreen 视图控制器中,您需要声明一个 QuizCompletedDelegate 类型的可选委托
var delegate: QuizCompletedDelegate?
...并在适当的时候使用该委托调用函数:
@IBAction func didPressContinue(_ sender: Any)
if allQuestionsAnswered == true
delegate.completedQuiz()
else
delegate.cancelledQuiz()
在您的初始视图中,控制器是您实现协议功能的地方:
extension ViewController: QuizCompletedDelegate
func completedQuiz()
//Handle quiz complete
func cancelledQuiz()
//Handle quiz cancelled
那么您需要做的最后一件事是在初始视图控制器的 prepareForSegue 函数中设置 ContinueScreen 视图控制器的委托。
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
if segue.identifier == "showContinueScreen"
let continueVC = segue.destination as! ContinueScreen
continueVC.delegate = self
在您的初始视图控制器的 ViewDidAppear 上删除对 randomQuestion() 的调用,您就可以开始工作了!
【讨论】:
if 语句中的 allQuestionsAnswered 是从哪里得到的? 这只是一个占位符,用于确定是否所有问题都已回答。这不是复制和粘贴代码,您需要对其进行一些调整以适应您要执行的具体操作。这就是你如何使用委托模式来完成你想要的。 感谢您的洞察,非常感谢! 没问题!如果您发现它有帮助,请随意投票和/或接受答案!【参考方案2】:返回时不应创建新的视图控制器。如果是这样 - 这很糟糕 - 你应该重新设计你的应用程序的流程......为了向前传递数据,我们应该使用依赖注入。要将数据传递给前一个视图控制器 - 使用 ios 委托模式。我建议花 30-40 分钟阅读(并理解这篇文章),它会让你以后更清楚:http://matteomanferdini.com/how-ios-view-controllers-communicate-with-each-other/。
【讨论】:
以上是关于向前传递后如何将数据向后传递给视图控制器?的主要内容,如果未能解决你的问题,请参考以下文章
接收到本地通知数据后如何创建使用目标 c 传递给主视图控制器?
如何使用按钮在 UIPageViewController 中向前和向后导航?