0

I'm working on a controller that will allow a user to set the number of players they would like in a game. The view consists of some labels, a slider, and a button. The slider allows the user to select a value from 1-4 to select the number of players. One of those labels is set to x Player(s) Selected where x is the slider's value rounded to the nearest Int. The button then sends the user to the game (another view) which is handled by a different View Controller (VC). I'm trying to send the number of players to the other VC but the value does not appear to be saved outside of the IBAction function.

As a possible fix, I've tried using an instance of GameViewController in NumberOfPlayersViewController.swift and updating the variable in setNumOfPlayers, which also did not work. Am I just missing something or is updating a variable in an IBAction not possible?

// NumberOfPlayersViewController.swift
import UIKit

class NumberOfPlayersViewCOntroller: UIViewController {
    // Default number of players
    var numOfPlayers = 1
    
    // UIObjects
    <Label here>
    <Slider here>

    @IBAction private func setNumOfPlayers(_ sender: UISlider) -> Void {
        // Get the number of players and update the label
        numOfPlayers = Int(sender.value) // Originally float, rounds the value to the nearest Int
        label.text = "\(numOfPlayers) Player(s) Selected" // Updates label
        print(numOfPlayers) // Prints the rounded value
    }

    func getNumberOfPlayers() -> Int {
        return numOfPlayers // Only returns the default value of 1
// GameViewController.swift
class GameViewController:UIViewController {
    let NumberOfPlayersVC = NumberOfPlayersViewController()
    lazy var numOfPlayers = NumberOfPlayersVC.getNumberOfPlayers() // Lazy as `self` is not available 

    override func viewDidLoad() {
        super.viewDidLoad()
        print(numOfPlayers) // Prints 1
    }
}

These views that these ViewControllers handle are connected via a Seque.

  • What's the relationship between GameViewController and NumberOfPlayersViewCOntroller? – El Tomato May 05 '21 at 23:44
  • @ElTomato They are both ViewControllers in my main project folder and they both control different views in the `Main.storyboard`. – DartRuffian May 06 '21 at 00:02
  • Tell us something that your code doesn't. How do they interact with each other? – El Tomato May 06 '21 at 00:09
  • @ElTomato The view that `NumberOfPlayersViewController` handles is the initial view, where a player selects a number of players from 1-4 with a slider. Then a button below the slider sends the user to the Game View using a Storyboard Segue. Other than that, they do not interact. I just want to send the value of the slider in the initial view to the game view controller. – DartRuffian May 06 '21 at 00:13
  • First, you need to know the purpose of viewDidLoad. Second, you need to find out how to pass a variable from view controller to another through Segue. For now, you have failed in both cases. – El Tomato May 06 '21 at 00:16
  • You need to edit your question to provide a complete description of your situation, the flow between view controllers, and the problem you are trying to solve. You should do this even if you found your own solution, so others can learn from what you've done. As it is people need to read your question, the comments on your question, the comments on other answers, and your answer in order to fully understand the question. – Duncan C May 07 '21 at 10:48

2 Answers2

0

Your GameViewController creates an instance of NumberOfPlayersViewController when it's created. In its viewDidLoad, you then fetch the value numOfPlayers. That lazy var will ask your NumberOfPlayersVC, once and only once, for the value of getNumberOfPlayers().

If that instance of NumberOfPlayersViewController has never been displayed to the screen and had the user update its slider and tap its button, it will still return a value of 1.

How do the 2 view controllers get displayed to the screen? When does the user get a chance to pick a value on your slider and tap the setNumOfPlayers button?

I don't see how that can happen between your GameViewController being initialized and its viewDidLoad method being invoked. That seems to be the problem. Your GameViewController is initialized, it creates a new instance of NumberOfPlayersViewCOntroller, its viewDidLoad method fires, its lazy var calls getNumberOfPlayers() on the NumberOfPlayersViewCOntroller, which returns 1 since that view controller hasn't been displayed on the screen yet. The lazy var will now always have a 1 in it.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • It seems I may have just misunderstood when I tried fetching the value when creating a new instance of `NumberOfPlayersViewController`. The view that `NumberOfPlayersViewController` handles is the initial view, which then transfers to the game view via a Storyboard Segue (which is what the button does). – DartRuffian May 06 '21 at 00:19
  • Thank you for all the help, but it turns out you can transfer data between controllers via `performSeque` and `prepare`. So I decided to use that method instead, although I now get a warning when the view changes. – DartRuffian May 06 '21 at 01:54
  • Yes, you certainly can pass data between view controllers in the segue method `prepare(for:sender:)`. However, I suspect you are confused about how to get to a view controller, collect information, and return to the original view controller. You should edit your question to show how you navigate between view controllers. – Duncan C May 06 '21 at 02:18
  • I know you can add a delegate protocol to a ViewController but I did not believe that would be the best choice as the user would never be returning to this screen. – DartRuffian May 07 '21 at 03:04
0

A solution to my problem was actually answered in this question: Passing variables between View Controllers using a segue, but I had missed it in my search. The solution involves using performSegue and prepare in order to transfer data between views. The answer also includes what to change in order to use this method in Swift 3+.