Moving data from Model to destination ViewController with segue - swift

I am new to Swift and programming in general. I am building a quiz app. The app uses TopicsViewController to select a topic and segue to a QuestionsViewController. The questions for the various topics are stored as separate Swift Objects file. I would like to pick the Topic1 Question file when I press the topic1 button in TopicsViewController to segue into the QuestionsViewController. I would like to know how can I select the particular questions file QuestionBank1/QuestionBank2 when I select the particular topic upon segueing to the QuestionsViewController?
Navigation Pane :
Main.storyboard :
TopicsViewController:
import UIKit
class TopicsViewController: UIViewController, returnToTopicVCDelegate {
func goToTopicVC() {
}
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func goToQuestionsVCWhenPressed(_ sender: UIButton) {
performSegue(withIdentifier: "segueToQuestionVC", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segueToQuestionVC" {
let quizVC = segue.destination as! QuizViewController
quizVC.delegate = self
}
}
}
QuizViewController:
import UIKit
import QuartzCore
protocol returnToTopicVCDelegate{
func goToTopicVC()
}
class QuizViewController: UIViewController {
var delegate : returnToTopicVCDelegate?
//outlet for the question label and image view
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var questionImageView: UIImageView!
//outlet for the buttons
#IBOutlet weak var optionAButton: UIButton!
#IBOutlet weak var optionBButton: UIButton!
#IBOutlet weak var optionCButton: UIButton!
#IBOutlet weak var optionDButton: UIButton!
#IBOutlet weak var optionEButton: UIButton!
//outlets for the progress
#IBOutlet weak var questionCounter: UILabel!
#IBOutlet weak var scoreLabel: UILabel!
var allQuestions = QuestionBank()
var selectedAnswer : Int = 0 // answer selected by the subject
var questionNumber: Int = 0
var score: Int = 0
// functions executed after an answer is picked
#IBAction func answerPressed(_ sender: UIButton) {
if sender.tag == selectedAnswer {
print("correct answer")
sender.backgroundColor = .green
score += 1
} else {
print("wrong")
sender.backgroundColor = .red
print("\(allQuestions.list[questionNumber].correctAnswer)")
//the following two lines change the right answer button to green using the tag value of the button
let correctAnswerButton = view.viewWithTag(selectedAnswer) as? UIButton
correctAnswerButton?.backgroundColor = UIColor.green
}
}
#IBAction func GoToNextQuestion(_ sender: UIButton) {
questionNumber += 1
nextQuestion()
}
// selects a new questions and updates the score
func nextQuestion(){
if questionNumber <= allQuestions.list.count - 1 {
questionLabel.text = allQuestions.list[questionNumber].question
questionImageView.image = UIImage(named: (allQuestions.list[questionNumber].questionImage))
optionAButton.setTitle(allQuestions.list[questionNumber].optionA, for: UIControlState.normal)
optionBButton.setTitle(allQuestions.list[questionNumber].optionB, for: UIControlState.normal)
optionCButton.setTitle(allQuestions.list[questionNumber].optionC, for: UIControlState.normal)
optionDButton.setTitle(allQuestions.list[questionNumber].optionD, for: UIControlState.normal)
optionEButton.setTitle(allQuestions.list[questionNumber].optionE, for: UIControlState.normal)
selectedAnswer = allQuestions.list[questionNumber].correctAnswer
updateUI()
} else {
let alert = UIAlertController(title: "Great!", message: "Do you want to start over?", preferredStyle: .alert)
let restartAction = UIAlertAction(title: "Restart", style: .default) {(UIAlertAction) in
self.restartQuiz()
}
alert.addAction(restartAction)
present(alert, animated: true, completion: nil)
}
}
func updateUI(){
scoreLabel.text = "score: \(score)"
questionCounter.text = "\(questionNumber + 1)/\(allQuestions.list.count)"
}
func restartQuiz(){
score = 0
questionNumber = 0
nextQuestion()
}
#IBAction func goBackToTopicsVC(_ sender: Any) {
delegate?.goToTopicVC()
dismiss(animated: true, completion: nil)
}
}

You can use the following steps :
1- Add a segue from TopicsViewController to QuestionsViewController and give the segue "Identifier Name " from Attributes inspector.
2- Add a variable in QuestionsViewController for the topic lets name it "topicType".
3- Override the below function in TopicsViewController and send the name of the topic with the segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Identifier Name" {
if let destinationviewController = segue.destination as? QuestionsViewController , let buttonPressed = sender as? UIButton {
destinationviewController.topicType = buttonPressed.currentTitle!
}
}
}
4- For each button in TopicsViewController , get the button action and type the following function in it :
#IBAction func topicButton(_ sender: UIButton) {
performSegue(withIdentifier: "Identifier Name", sender: nil)
}
I hope this helps you .

Related

Error : "Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffee0234ff0)"

I have this code and when I am running the App on the line with "super.viewDidLoad()", I have the "Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffee0234ff0" error...
Can someone help me please?
On internet they say me that I have to connect my Developer Account, but I don't have one.
This is the code :
import Foundation
import UIKit
import FirebaseAuth
import FirebaseDatabase
class SignUpController : UIViewController {
//Fonction pour scroller
private let scrollView: UIScrollView = {
let scrollView = UIScrollView.self()
scrollView.clipsToBounds = true
return scrollView
}()
//MARK : Outlets
#IBOutlet weak var artistnameTextField: UITextField!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var confirmationPasswordTextField: UITextField!
#IBOutlet weak var signupButton: UIButton!
#IBOutlet weak var loginButton: UIButton!
//MARK : Properties
override func viewDidLoad() {
super.viewDidLoad()
viewDidLoad()
//Add subviews
view.addSubview(scrollView)
scrollView.addSubview(artistnameTextField)
scrollView.addSubview(emailTextField)
scrollView.addSubview(passwordTextField)
scrollView.addSubview(confirmationPasswordTextField)
scrollView.addSubview(signupButton)
scrollView.addSubview(loginButton)
//Design
setupButtons()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showLogin" {
let VCDestination = segue.destination as! LoginController
VCDestination.myMail = emailTextField.text!
}
if segue.identifier == "showLogin" {
let VCDestination = segue.destination as! LoginController
VCDestination.myPassword = passwordTextField.text!
}
}
//MARK : Private Methods
private func setupButtons() {
signupButton.layer.cornerRadius = 20
loginButton.layer.cornerRadius = 20
loginButton.layer.borderWidth = 3
loginButton.layer.borderColor = UIColor.lightGray.cgColor
}
private func setupTextFieldManager() {
artistnameTextField.delegate = self
emailTextField.delegate = self
passwordTextField.delegate = self
let tapGesture = UITapGestureRecognizer (target: self, action: #selector(hideKeyboard))
view.addGestureRecognizer(tapGesture)
}
//MARK : Actions
#IBAction func signUpButton(_ sender: UIButton) {
performSegue(withIdentifier: "showLogin", sender: nil)
}
#objc private func hideKeyboard() {
artistnameTextField.resignFirstResponder()
emailTextField.resignFirstResponder()
passwordTextField.resignFirstResponder()
}
#IBAction func signupButtonWasPressed(_ sender: UIButton) {
if artistnameTextField !== "" as AnyObject && emailTextField !== "" as AnyObject && passwordTextField !== "" as AnyObject && confirmationPasswordTextField.text == passwordTextField.text {
Auth.auth().createUser(withEmail: emailTextField.text!, password: passwordTextField.text!) { (authResult, error) in
if error != nil {
print(error.debugDescription)
self.alertUserLoginError()
} else {
print ("Inscription en cours...")
let ref = Database.database().reference()
let userID = Auth.auth().currentUser?.uid
ref.child("users").child(userID!).setValue(["artistName": self.artistnameTextField.text])
self.performSegue(withIdentifier: "goToHome", sender: self)
}
}
} else {
print("Veuillez remplir tous les champs.")
}
}
#IBAction func loginButtonWasPressed(_ sender: UIButton) {
print("Redirection vers l'écran de connexion...")
}
func alertUserLoginError() {
let alert = UIAlertController(title: "Erreur", message: "Veuillez remplir tous les champs", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Dismiss", style: .cancel, handler: nil))
present(alert, animated: true)
}
}
extension SignUpController: UITextFieldDelegate{
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
Thanks
Ok so for the sake of brevity, here's a concept called "App Lifecycle" which by its nature is the methods that are called by the iOS system and in a specific order. Remember that computers can only run one thing at a time, per CPU. So it must go in an order of some sort. The iOS lifecycle events are as follows.
loadView()
viewDidLoad()
viewWillAppear()
viewDidAppear()
didReceiveMemoryWarning()
viewWillDisappear()
viewDidDisappear()
Now bear in mind there are a few others depending on what you're doing but these are the most common ones.
With 90% of these lifecycle methods, there's something more that is going on in the background that you don't see. This is where the super.methodName() call comes into play. It allows you to add additional functionality at a given lifecycle event without losing any of the other functionality that is being provided by that method. Otherwise, you might lose something that is required to load the view. Eg, super.methodName retains all previous functionality.
Now, to your issue, you have the following lines of code.
override func viewDidLoad() {
super.viewDidLoad()
viewDidLoad()
//A bunch more code after this.
}
Looking at the Lifecycle methods, that are required in many cases, notice that you are calling viewDidLoad() inside of your super.viewDidLoad which means that your main thread gets stuck. It loops back through that method that called it, and then there it is again, another viewDidLoad() call. In turn, it loops, again, and again, and again, until it crashes. There is a time and a place for recursion, however, this is not one of them, and that's for a completely separate topic.
Ultimately your solution is to remove the viewDidLoad() method call after your super.viewDidLoad() and that will resolve the error that you're having.

How to pass different URL to webView from some buttons in swift?

I have some buttons in first view controller and a webView in second view controller. How to pass different url from different buttons to the webView? For example, the first button will leads to a google website and the second one is Facebook but using the same webView. Do I need to create different segues for each button or just one? If using just one, where should I start pulling that blue line (that line when you hold the control key)?
In first viewController:
class CafesView: UIViewController {
#IBOutlet weak var topBar: UIView!
#IBOutlet weak var button1: MDCFloatingButton!
#IBOutlet weak var button2: MDCRaisedButton!
#IBOutlet weak var button3: MDCRaisedButton!
#IBOutlet weak var button4: MDCRaisedButton!
#IBOutlet weak var button5: MDCRaisedButton!
#IBOutlet weak var button6: MDCRaisedButton!
#IBOutlet weak var button7: MDCRaisedButton!
#IBOutlet weak var button8: MDCRaisedButton!
#IBOutlet weak var button9: MDCRaisedButton!
let cafes = [
"Banana Joe's",
"College Eight Cafe",
"Global Village",
"Iveta",
"Oakes Cafe",
"Perk Coffee Bar",
"Stevenson Coffee House",
"Terra Fresca",
"Vivas"
]
var urlToPass: String!
override func viewDidLoad() {
super.viewDidLoad()
topBar.layer.shadowColor = UIColor.black.cgColor
topBar.layer.shadowOpacity = 0.5
topBar.layer.shadowOffset = CGSize(width: 0, height: 2)
topBar.layer.shadowRadius = 5
button1.layer.cornerRadius = 20
button2.layer.cornerRadius = 20
button3.layer.cornerRadius = 20
button4.layer.cornerRadius = 20
button5.layer.cornerRadius = 20
button6.layer.cornerRadius = 20
button7.layer.cornerRadius = 20
button8.layer.cornerRadius = 20
button9.layer.cornerRadius = 20
}
#IBAction func bananaJoes(_ sender: UIButton) {
urlToPass = "https://dining.ucsc.edu/pdf/banana-joes-menu.pdf"
}
#IBAction func collegeEightCafe(_ sender: UIButton) {
urlToPass = "https://dining.ucsc.edu/pdf/c8-menu.pdf"
}
#IBAction func globalVillage(_ sender: Any) {
urlToPass = "https://www.foodbooking.com/ordering/restaurant/menu?restaurant_uid=d368abee-3ccc-40d7-be7f-3ca5d4cbd513&glfa_cid=1263531392.1571083521&glfa_t=1571083566919"
}
#IBAction func iveta(_ sender: UIButton) {
urlToPass = "https://iveta.com/pages/iveta-ucsc-menu"
}
#IBAction func oakesCafe(_ sender: UIButton) {
urlToPass = "https://dining.ucsc.edu/pdf/oakes-menu-2019-20.pdf"
}
#IBAction func perkCoffeeBar(_ sender: UIButton) {
urlToPass = "https://google.com" //This url is just a placeholder
}
#IBAction func stevensonCoffeeHouse(_ sender: UIButton) {
urlToPass = "https://dining.ucsc.edu/pdf/stevenson-coffee-house-menu.pdf"
}
#IBAction func terraFresca(_ sender: UIButton) {
urlToPass = "https://dining.ucsc.edu/terra-fresca/pdf/terra-fresca-menu.pdf"
}
#IBAction func vivas(_ sender: UIButton) {
urlToPass = "https://dining.ucsc.edu/pdf/vivas-menu.pdf"
}
#IBAction func dismiss(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
guard let destination = segue.destination as? CafesMenu else { return }
destination.detailURL = urlToPass
urlToPass = nil
}
}
In the second one:
import UIKit
import WebKit
class CafesMenu: UIViewController {
#IBOutlet weak var webView: WKWebView!
var detailURL: String?
override func viewDidLoad() {
super.viewDidLoad()
print("URL Requested: \(detailURL)")
}
override func viewWillAppear(_ animated: Bool) {
let url = URL(string: detailURL!)
let request = URLRequest(url: url!)
webView.load(request)
}
#IBAction func dismiss(_ sender: UIBarButtonItem) {
self.dismiss(animated: true, completion: nil)
}
}
What you need to do is use prepareForSegue:sender: to set a property in your destination view controller. prepareForSegue:sender: will be called before your initial view controller segues to any destination view controller. Within this function, we can check which button was pressed and set the appropriate URL in the destination view controller accordingly.
This approach will allow you to use any segue between your buttons and your destination view controller. This means, you simply have to drag the blue line from the buttons to the view controller you want to segue to.
1. Within your storyboard, create a segue between your first view controller and your destination view controller. This is done by holding control, clicking on the first view controller in the interface builder, and dragging over the destination view controller. Then choose a segue type:
Now, select this segue and give it the Identifier "InitialVCToDestinationVC" in the attributes inspector:
2. Make a property called urlToPass of type URL in your initial view controller:
class InitialViewController: UIViewController {
var urlToPass: URL!
#IBAction func googleButtonPressed(_ sender: Any) {
}
#IBAction func facebookButtonPressed(_ sender: Any) {
}
}
3. Make a property called receivedUrl in the destination view controller:
class DestinationViewController: UIViewController {
var receivedUrl: URL!
#IBOutlet var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let request = URLRequest(url: receivedUrl)
webView.load(request)
}
}
4. Set the urlToPass depending on which button is pressed and use the prepareForSegue:sender: function to set the destination view controller's url accordingly. Then, make use of performSegue(withIdentifier:sender:) to perform the segue with identifier InitialVCToDestinationVC.
class InitialViewController: UIViewController {
var urlToPass: URL!
#IBAction func googleButtonPressed(_ sender: Any) {
urlToPass = URL(string: "www.google.com")
performSegue(withIdentifier: "InitialVCToDestinationVC", sender: nil)
}
#IBAction func facebookButtonPressed(_ sender: Any) {
urlToPass = URL(string: "www.facebook.com")
performSegue(withIdentifier: "InitialVCToDestinationVC", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
guard let destination = segue.destination as? DestinationViewController else { return }
destination.receivedUrl = urlToPass
urlToPass = nil
}
}
5. (optional) Make use of the shouldPerformSegueWithIdentifier:sender: method within InitialViewController and check whether or not urlToPass is valid. If urlToPass is valid, perform the segue, else present an alert.
class InitialViewController: UIViewController {
...
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if let urlToPass = urlToPass {
// check if your application can open the NSURL instance
if !UIApplication.shared.canOpenURL(urlToPass) {
let alertController = UIAlertController(title: "Cannot open URL.", message: "This is an invalid URL.", preferredStyle: .alert)
let ok = UIAlertAction(title: "Okay", style: .cancel, handler: nil)
alertController.addAction(ok)
present(alertController, animated: true, completion: nil)
}
return UIApplication.shared.canOpenURL(urlToPass)
}
return false
}
}
End result:
Here's a link to the Xcode project I made the above gif from: https://github.com/ChopinDavid/PrepareForSegue
Try using the following code snippet to pass the urlParameter to second viewcontroller
class FirstViewController: UIViewController{
func googleActionButton() {
let vc = SecondViewController()
vc.urlToOpen = "www.google.com"
self.present(vc, animated: true, completion: nil)
}
func facebookActionButton() {
let vc = SecondViewController()
vc.urlToOpen = "www.facebook.com"
self.present(vc, animated: true, completion: nil)
}
}
class SecondViewController: UIViewController{
var urlToOpen = String()
override func viewDidLoad() {
super.viewDidLoad()
// set webview url to the 'urlToOpen' which you received from FirstViewController
}
}
First of all, create an enum WebURL with all the url cases that you want to open, i.e.
enum WebURL {
case google
case facebook
var url: String {
switch self {
case .google:
return "https://www.google.com"
case .facebook:
return "https://www.facebook.com"
}
}
}
Next, in FirstVC, in the UIButton's #IBAction open SecondVC using the WebURL instance corresponding to that particular button, i.e.
class FirstVC: UIViewController{
#IBAction func openGoogle(_ sender: UIButton) {
self.openSecondVC(with: WebURL.google.url)
}
#IBAction func openFacebook(_ sender: UIButton) {
self.openSecondVC(with: WebURL.facebook.url)
}
func openSecondVC(with urlString: String) {
if let vc = self.storyboard?.instantiateViewController(withIdentifier: "SecondVC") as? SecondVC {
vc.urlString = urlString
self.present(vc, animated: true, completion: nil)
}
}
}
Then, use urlString in SecondVC to configure your webView, i.e.
class SecondVC: UIViewController {
var urlString: String?
override func viewDidLoad() {
super.viewDidLoad()
//Setup your webView using urlString here...
}
}

How can I properly send values between classes in Swift?

I've been working on a text based adventure game using Swift. However, I can't seem to change the default values for specific classes.
Below is the code for the class that allows me to select my player class
import UIKit
class ClassSelectionController: UIViewController
{
//Default class values
var character = (0, 0, "", 0)
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
}
//class button actions
#IBAction func fighterBtn(_ sender: Any)
{
character = (50, 60, "Steal Sword", 18)
performSegue(withIdentifier: "Character", sender: self)
}
#IBAction func wizerdBtn(_ sender: Any)
{
character = (25, 70, "Staff", 15)
performSegue(withIdentifier: "Character", sender: self)
}
#IBAction func thiefBtn(_ sender: Any)
{
character = (30, 60, "Dagger", 18)
performSegue(withIdentifier: "Character", sender: self)
}
#IBAction func archerBtn(_ sender: Any)
{
character = (50, 60, "Bow & Arrow", 16)
performSegue(withIdentifier: "Character", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: (Any)?)
{
//code for segue
var vc = segue.destination as! ViewController
vc.finalCharacter = self.character
}
}
And this is the class that receives the data for the player class and displays it.
import UIKit
class ViewController: UIViewController
{
var finalCharacter = (0, 0, "", 0)
//****************************************
//Setup for outlets go between these lines
//****************************************
#IBOutlet weak var healthLabel: UILabel!
#IBOutlet weak var damageLabel: UILabel!
#IBOutlet weak var weaponLabel: UILabel!
#IBOutlet weak var armorLabel: UILabel!
#IBOutlet weak var storyLabel: UILabel!
#IBOutlet weak var actionButton: UIButton!
#IBOutlet weak var northBtn: UIButton!
#IBOutlet weak var southBtn: UIButton!
#IBOutlet weak var eastBtn: UIButton!
#IBOutlet weak var westBtn: UIButton!
//****************************************
//Setup for outlets go between these lines
//****************************************
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
healthLabel.text = "Health: \(finalCharacter.0)"
damageLabel.text = "Damage: \(finalCharacter.1)"
weaponLabel.text = "Weapon: " + finalCharacter.2
armorLabel.text = "Armor : \(finalCharacter.3)"
}
//****************************************
//Setup for buttons go between these lines
//****************************************
#IBAction func actionButton(_ sender: Any)
{
}
#IBAction func northButton(_ sender: Any)
{
}
#IBAction func southButton(_ sender: Any)
{
}
#IBAction func eastButton(_ sender: Any)
{
}
#IBAction func westButton(_ sender: Any)
{
}
//****************************************
//Setup for buttons go between these lines
//****************************************
}
Even though my code does not currently show it I did put print values in the class buttons just so see if the values have changed when I select a class and I have seen that they do change when the button is pressed. I also poked around in ViewController and changed the finalCharacter values, just to see if that affected anything, which it didn't. So my educated guess is that the problem has to be in ClassSelectionController.
So the main problem is that I will click on the wizard player class, and I'd expect the class stats for the wizard to pop up (I.e. 25, 70, "Staff", 15), but I'll only get the default values that are in the ClassSelectionController (0, 0, "", 0).
What is happening here that you have multiple UIStoryboardSegue named "Character" linked with every button
so what happens is when you press the button the Segue is called before the Action button and in addition the UIStoryboardSegue is called again (if you place a debugger in the viewDidLoad you would see that it goes there two times).
Solution
Remove all the UIStoryboardSegue linked from the buttons
Make a new UIStoryboardSegue from the ClassSelectionController to the next ViewController name it 'Character'
You dont need to change anything from the code but should add a safe check
override func prepare(for segue: UIStoryboardSegue, sender: (Any)?)
{
if (segue.identifier == "Character") {
let vc = segue.destination as! ViewController
vc.finalCharacter = self.character
}
}

Text field is permanently in the second view controller upon segue

I have been working on an app that allows multiple text fields from the first view controller pass over to the second view controller upon pressing a button. However, the text fields are permanently in the second view controller when I only want them to be if the button is pressed. Here is the code for the first view controller! Any help is greatly appreciated.
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var textField1: UITextField!
#IBAction func buttonTwo(_ sender: Any) {
if textField1.text != "" {
performSegue(withIdentifier: "segue", sender: self)
}
}
#IBAction func buttonOne(_ sender: Any) {
if textField.text != "" {
performSegue(withIdentifier: "segue", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var secondController = segue.destination as! SecondViewController
secondController.myString1 = textField1.text!
secondController.myString = textField.text!
}
}
Here is the code in the second view controller:
class SecondViewController: UIViewController {
#IBOutlet weak var label: UILabel!
#IBOutlet weak var label1: UILabel!
var myString = String()
var myString1 = String()
override func viewDidLoad() {
super.viewDidLoad()
label.text = myString
label1.text = myString1
// Do any additional setup after loading the view.
}
}
Image of storyboard
This happens because, prepare for segue will be called every time you perform some segue action.
You should manage to have a bool variable that helps you track, if any button is clicked or not, if the segue is performed from the click of the button, then only you will have to set the text while preparing for segue.
here is your updated viewController
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var textField1: UITextField!
var isButtonClicked: Bool = false
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
/*reset isButtonClicked to false, when you back from second viewController */
isButtonClicked = false
}
#IBAction func buttonTwo(_ sender: Any) {
if textField1.text != "" {
isButtonClicked = true
performSegue(withIdentifier: "segue", sender: self)
}
}
#IBAction func buttonOne(_ sender: Any) {
if textField.text != "" {
isButtonClicked = true
performSegue(withIdentifier: "segue", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if isButtonClicked {
var secondController = segue.destination as! SecondViewController
secondController.myString1 = textField1.text!
secondController.myString = textField.text!
}
}
}
Try and share your results.

selecting with UIButton and moving a specific model data with segue

I am new to swift and new to programming in general. I am building a quiz app. I want to select a topic in a TopicViewController and move to a new Quizviewcontroller that will display the question and answer choices. I have multiple question bank that I believe are objects of a class Question. I am able to move to the QuizViewConctroller with segue but unable to select the Question bank based on the topic UI button selected.
I have tried and spent days trying to figure this out. I have looked at similar posts in SO. I have posted this question before but did not get any reply. I would really appreciate if someone could help. I don't know how else to proceed...
TopicsViewController:
import UIKit
class TopicsViewController: UIViewController, ReturnToTopicVCDelegate {
func goToTopicVC() {}
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func goToQuestionsVCWhenPressed(_ sender: UIButton) {
performSegue(withIdentifier: "segueToQuestionVC", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segueToQuestionVC" {
let quizVC = segue.destination as! QuizViewController
quizVC.delegate = self
}
}
}
QuizViewController:
import UIKit
import QuartzCore
protocol ReturnToTopicVCDelegate {
func goToTopicVC()
}
class QuizViewController: UIViewController {
var delegate: ReturnToTopicVCDelegate?
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var questionImageView: UIImageView!
#IBOutlet weak var optionAButton: UIButton!
#IBOutlet weak var optionBButton: UIButton!
#IBOutlet weak var optionCButton: UIButton!
#IBOutlet weak var optionDButton: UIButton!
#IBOutlet weak var optionEButton: UIButton!
//outlets for the progress
#IBOutlet weak var questionCounter: UILabel!
#IBOutlet weak var scoreLabel: UILabel!
var allQuestions = QuestionBank()
var selectedAnswer: Int = 0 // answer selected by the subject
var questionNumber: Int = 0
var score: Int = 0
#IBAction func answerPressed(_ sender: UIButton) {
if sender.tag == selectedAnswer {
print("correct answer")
sender.backgroundColor = .green
score += 1
} else {
print("wrong")
sender.backgroundColor = .red
print("\(allQuestions.list[questionNumber].correctAnswer)")
//the following two lines change the right answer button to green using the tag value of the button
let correctAnswerButton = view.viewWithTag(selectedAnswer) as? UIButton
correctAnswerButton?.backgroundColor = UIColor.green
}
}
#IBAction func GoToNextQuestion(_ sender: UIButton) {
questionNumber += 1
nextQuestion()
}
func nextQuestion() {
if questionNumber <= allQuestions.list.count - 1 {
questionLabel.text = allQuestions.list[questionNumber].question
questionImageView.image = UIImage(named: (allQuestions.list[questionNumber].questionImage))
optionAButton.setTitle(allQuestions.list[questionNumber].optionA, for: .normal)
optionBButton.setTitle(allQuestions.list[questionNumber].optionB, for: .normal)
optionCButton.setTitle(allQuestions.list[questionNumber].optionC, for: .normal)
optionDButton.setTitle(allQuestions.list[questionNumber].optionD, for: .normal)
optionEButton.setTitle(allQuestions.list[questionNumber].optionE, for: .normal)
selectedAnswer = allQuestions.list[questionNumber].correctAnswer
updateUI()
} else {
let alert = UIAlertController(title: "Great!", message: "Do you want to start over?", preferredStyle: .alert)
let restartAction = UIAlertAction(title: "Restart", style: .default) { (UIAlertAction) in
self.restartQuiz()
}
alert.addAction(restartAction)
present(alert, animated: true, completion: nil)
}
}
func updateUI() {
scoreLabel.text = "score: \(score)"
questionCounter.text = "\(questionNumber + 1)/\(allQuestions.list.count)"
}
func restartQuiz() {
score = 0
questionNumber = 0
nextQuestion()
}
#IBAction func goBackToTopicsVC(_ sender: Any) {
delegate?.goToTopicVC()
dismiss(animated: true, completion: nil)
}
}
The Questions are in this format
import Foundation
class QuestionBank {
var list = [Question]()
init() {
let skyColorQuestion = Question(questionText: “What is the color of sky?", image: "sky", choiceA: "blue", choiceB: "black", choiceC: "yellow", choiceD: "pink", choiceE: "None of the above", answer: 1)
let whatQuestion = Question(questionText: “what…?”, image: "image", choiceA: "x", choiceB: "y", choiceC: "z", choiceD: "m", choiceE: "None of the above", answer: 3)
list.append(skyColorQuestion)
list.append(whatQuestion)
}
}
Navigation Pane
Storyboard
Add the data are not correct in this way. My recommendation you can use a Realm, sqLite, CoreData or FireBase.