In my Swift iOS app, I have implemented an UIAlertController to display a message with "Yes" and "No" buttons. The "Yes" button correctly resets the game, but when you tap the "No" button, the alert controller does not dismiss as expected (I want to navigate back to SecondViewController). This is my code right now for SecondViewController (this is where I want to navigate back to)
import UIKit
class SecondViewController: UIViewController {
let TO_GAME_SCREEN = "toGameScreen"
var playAgainstComputer = GameSettings.shared.playAgainstComputer
var logicAndRules = LogicAndRules()
@IBOutlet weak var txtPlayerOne: UITextField!
@IBOutlet weak var txtPlayerTwo: UITextField!
@IBOutlet weak var btnNavigate: UIButton!
@IBOutlet weak var btnPlayNPC: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
txtPlayerOne.text = ""
txtPlayerTwo.text = ""
}
@IBAction func btnNavigate(_ sender: UIButton) {
GameSettings.shared.playAgainstComputer = false
guard let playerOneName = txtPlayerOne.text, !playerOneName.isEmpty, !isNumeric(input: playerOneName) else {
// Visa ett felmeddelande om användaren skriver ett nummer
showAlert(message: "Invalid player name for Player 1")
return
}
guard let playerTwoName = txtPlayerTwo.text, !playerTwoName.isEmpty, !isNumeric(input: playerTwoName) else {
// Visa ett felmeddelande om användaren skriver ett nummer
showAlert(message: "Invalid player name for Player 2")
return
}
performSegue(withIdentifier: TO_GAME_SCREEN, sender: self)
}
func isNumeric(input: String) -> Bool {
return Int(input) != nil
}
func showAlert(message: String) {
let alertController = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(okAction)
present(alertController, animated: true, completion: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == TO_GAME_SCREEN {
if let destinationVC = segue.destination as? GameViewController {
guard let txtPlayerOne = txtPlayerOne.text else {return}
guard let txtPlayerTwo = txtPlayerTwo.text else {return}
destinationVC.logicAndRules.playerOneName = txtPlayerOne.isEmpty ? "X" : txtPlayerOne
destinationVC.logicAndRules.playerTwoName = txtPlayerTwo.isEmpty ? "O" : txtPlayerTwo
}
}
}
@IBAction func btnPlayNPC(_ sender: UIButton) {
GameSettings.shared.playAgainstComputer = true
txtPlayerOne.text = "Player"
txtPlayerTwo.text = "Computer"
performSegue(withIdentifier: TO_GAME_SCREEN, sender: self)
}
}
And this is my code in GameViewController where I actually have my alertMessage:
import UIKit
class GameViewController: UIViewController { // hanterar användargränssnittet
// All my outlets
@IBOutlet weak var turnSign: UILabel!
@IBOutlet var buttons: [UIButton]!
let playAgainstComputer = GameSettings.shared.playAgainstComputer
var logicAndRules = LogicAndRules()
override func viewDidLoad() {
super.viewDidLoad()
logicAndRules.boardArray = ["", "", "", "", "", "", "", "", ""]
if (logicAndRules.currentPlayer == 1) {
turnSign.text = logicAndRules.playerOneName
} else {
turnSign.text = logicAndRules.playerTwoName
}
}
func switchPlayers() {
logicAndRules.switchPlayers()
}
func resetGame() {
logicAndRules.boardArray = ["", "", "", "", "", "", "", "", ""]
for button in buttons {
button.setTitle("", for: .normal)
button.isEnabled = true
}
logicAndRules.currentPlayer = 1
turnSign.text = logicAndRules.playerOneName
}
func makeComputerMove() {
var emptySpots = [Int]()
for (index, value) in logicAndRules.boardArray.enumerated(){
if value.isEmpty{
emptySpots.append(index)
}
}
if let randomIndex = emptySpots.randomElement(){
let buttonToPress = buttons[randomIndex]
buttonTapped(buttonToPress)
}
}
func playAgainstNPC() {
logicAndRules.playAgainstNPC()
makeComputerMove()
}
func myAlertMessage(winnerMessage: String){
let crossesText = "Crosses: \(logicAndRules.countPLayer1)"
let noughtsText = "Noughts: \(logicAndRules.countPlayer2)"
let messageText = "Do you wanna play again?\n\n\(crossesText)\n\(noughtsText)"
let myAlertController = UIAlertController(title: winnerMessage, message: messageText, preferredStyle: .alert)
let yesAction = UIAlertAction(title: "Yes", style: .default){_ in
self.resetGame()
}
let noAction = UIAlertAction(title: "No", style: .cancel){_ in
self.dismiss(animated: true)
}
myAlertController.addAction(yesAction)
myAlertController.addAction(noAction)
present(myAlertController, animated: true, completion: nil)
}
/**
In this function I want to set a title on a button and then switch turn when a button is pressed
All the buttons are attached to this function so that "let index" will include same terms for all my buttons
**/
@IBAction func buttonTapped(_ sender: UIButton) {
let index = sender.tag
if logicAndRules.boardArray[index] == ""{
if logicAndRules.currentPlayer == 1 {
logicAndRules.boardArray[index] = "X"
sender.setTitle("X", for: .normal)
} else {
logicAndRules.boardArray[index] = "O"
sender.setTitle("O", for: .normal)
}
sender.setTitle(logicAndRules.boardArray[index], for: .normal)
logicAndRules.switchPlayers()
if logicAndRules.currentPlayer == 1 {
turnSign.text = logicAndRules.playerOneName
} else {
turnSign.text = logicAndRules.playerTwoName
}
if let winnerMessage = logicAndRules.checkForWinner() {
logicAndRules.winner = winnerMessage
myAlertMessage(winnerMessage: winnerMessage)
}
} else if !logicAndRules.boardArray.contains("") {
myAlertMessage(winnerMessage: "It's a tie!")
}
if GameSettings.shared.playAgainstComputer && logicAndRules.currentPlayer == 2 {
playAgainstNPC()
}
}
}
I have attempted to dismiss the alert controller using
myAlertController?.dismiss(animated: true, completion: nil)
, but this does not work. the alert controller remains on the screen, and the expected behavior of dismissing the alert when the "No" button is pressed is not being achieved.
dismissis only going to work if the view controller was shown withpresent. How are you displayingGameViewController? It looks like a segue is being used. How is it setup?dismisswithpopViewControlleron the navigation controller.