How do I update a label in a different view controller? - swift

I’m very new to coding. I created a game and there is a scoreLabel in the top corner of GameViewController. I created another label in a different view controller (ShopViewController) called moneyLabel. I want the money label to be equal to the score. I made it so that my score label resets every time you start a new game, but I want my money to stay the same so that I can use the money for purchases in game.
I don’t know how to make it update. I tried: gameViewController = GameViewController() and then using code to update my label but it’s not working. My label isn’t updating at all. It stays at 0.

I think you have to use some model struct where you can add your score or any other data and easily manipulate it:
struct GameData{
var totalScore: Int = 0
var currentGameScore: Int = 0
func invalidateCurrentScore(){
totalScore += currentGameScore
currentGameScore = 0
//call this method when you need to set your current score to 0, and pass all the accumulated points to your total score (f.ex. in the end of the game)
}
//some other data like player's name and etc...
}
You also need to create a delegation protocol for using its method in ShopViewController and returning the game data to GameViewController:
protocol ShopViewControllerDelegate{
func updateGameData(by gameData: GameData)
}
GameViewController with new parts:
class GameViewConroller: UIViewController, ShopViewControllerDelegate{
#IBOutlet weak var scoreLabel: UILabel!
var gameData: GameData!
override func viewDidLoad(){
super.viewDidLoad()
gameData = GameData()
updateScoreLabel()
}
private func updateScoreLabel(){ //call it anyTime when you manipulate the score of current game
scoreLabel.text = "Score: \(gameData.currentGameScore)"
}
func updateGameData(by gameData: GameData){ //This is the delegate's method that ShopViewController needs to trigger when you buy something in the shop
self.gameData = gameData
updateScoreLabel()
}
override func prepare(for segue: UIStoryboardSegue,
sender: Any?){
if let shopViewController = segue.destination as? ShopViewController{
//passing game data to ShopViewController
shopViewController.gameData = self.gameData
shopViewController.delegate = self //!IMPORTANT
}
}
}
And these are some properties and methods that your ShopViewController should have:
class ShopViewController{
#IBOutlet weak var totalScoreLabel: UILabel!
var gameData: GameData!
var delegate: ShopViewControllerDelegate?
override func viewDidLoad(){
super.viewDidLoad()
updateTotalScoreLabel()
}
private func updateTotalScoreLabel(){
totalScoreLabel.text = "Total Score: \(gameData.totalScore + gameData.currentGameScore)"
}
private func purchasingSomething(){
//logic of getting price of an item
gameData.currentGameScore -= price
if gameData.currentGameScore < 0{
gameData.totalScore += gameData.currentGameScore
gameData.currentGameScore = 0
//if your current score is less than 0 after some purchase, your total score decreases and the current score becomes 0
}
updateTotalScoreLabel()
delegate?.updateGameData(by gameData: gameData) //Pass refreshed gameData back to the GameViewController
}
}
Also Swift has static variables, but it's very easy to use. Delegates bring more fun and makes code more pretty.
struct GameData{
static var totalScore: Int = 0
static var currentGameScore: Int = 0
}
Good luck and have fun with the game dev :)

Related

How to random position from UIButtons has created by storyboard?[swift Xcode]

I created 12 UIButtons by storyboard, in my program, these buttons represent cards,I want to random the buttons' position for shuffling the cards.please do me a favor, give a way or idea to achieve it.
my buttons problem
import UIKit
class ViewController: UIViewController {
lazy var game = Concentration(numberOfPairsOfCards: numberOfPairOfCards) //引入model Concentration
var numberOfPairOfCards : Int {
return (cardButtons.count + 1) / 2 //read only computed properties可以省略get{}
}
var flipCount = 0 {
didSet {
flipsCountLabel.text = "Flips: \(flipCount)"
}
}
#IBOutlet var cardButtons: [UIButton]!
#IBOutlet weak var flipsCountLabel: UILabel!
#IBAction func touchCard(_ sender: UIButton) {
flipCount += 1
if let cardNumber = cardButtons.index(of: sender) {
game.chooseCard(at: cardNumber)
updateViewFromModel()
} else {
print("somthing wrong")
}
}
I have done the job.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var buttons = [UIButton]()
for index in cardButtons.indices {
buttons.append(cardButtons[index])
}
for index in cardButtons.indices {
cardButtons[index] = buttons.remove(at: buttons.count.arc4random)
}
}
You could add the buttons to an array, shuffle the array and then loop through it and place the buttons. A better solution would be to create a UICollectionView instead though.

How to implement the data source for multiple combo boxes in the same view controller

I have 2 combo boxes that use the same dictionary as the data source. in the first combo box the keys will be displayed and in the second one the values will be displayed.
First I need a bit of help with implementing the data source delegate methods; please see code listing below. the relevant boxes are floorsBox and roomsBox. Ignore the other 2 as they will be populated from a local variable or from the interface.
Also, lets say that for the first floor [key = 0] i have 3 rooms [value = 3], how do I take the value of 3 and make it into 3 items inside the roomsBox; So that every time the floor changes the box for the rooms has the corresponding number of items (if that makes sense). I really do appreciate your help and I thank you.
class RoomAndAlarmTypesVC: NSViewController, NSComboBoxDelegate, NSComboBoxDataSource {
//MARK: - Properties
private var floorsAndRooms = [String: String]()
#IBOutlet private weak var floorsBox: NSComboBox!
#IBOutlet private weak var roomsBox: NSComboBox!
#IBOutlet private weak var roomType: NSComboBox!
#IBOutlet private weak var alarmType: NSComboBox!
//MARK: - Actions
override func viewDidLoad() {
super.viewDidLoad()
floorsAndRooms = representedObject as! [String : String]
floorsBox.usesDataSource = true
roomsBox.usesDataSource = true
roomType.usesDataSource = true
alarmType.usesDataSource = true
floorsBox.delegate = self
roomsBox.delegate = self
roomType.delegate = self
alarmType.delegate = self
floorsBox.dataSource = self
roomsBox.dataSource = self
roomType.dataSource = self
alarmType.dataSource = self
}
#IBAction private func setTheSystem(_ sender: NSButton) {
}
func numberOfItems(in comboBox: NSComboBox) -> Int {
what do i do here?
}
func comboBox(_ comboBox: NSComboBox, objectValueForItemAt index: Int) -> Any? {
same here?
}
}
Use a switch statement based on the sender (your comboBox parameter)
for example:
switch comboBox
{
case floorsBox : return // the data for floors
case roomsBox : return // the data for rooms
...
}

acessing variables from one class to another in swift

In the app the user types in infomations as integers into two different textfields. After a action button click the user now access two other textfields which the user again types data as integers. Now after a click on a button I want a label's text to show this typed in information from the two situations earlier
However in my code, I can't access my variables (the information from the user input) because this label's text is in a new class and the user input variables are stored in two other classes).
How can I access these variables in my new class where my label is?
An example of my code:
#IBOutlet var nextStagetwo: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func check(sender: AnyObject) {
var strValue = boxShots.text
var floatValue = Double((strValue as! NSString).integerValue)
var strValue2 = boxMakes.text
var floatValue2 = Double((strValue2 as! NSString).integerValue)
var stage = "stage 2"
var procent = floatValue2 / floatValue * 100
enter code here
I now want to access my variable procent in this class:
class stagethree: UIViewController {
#IBOutlet var stats: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func check(sender: AnyObject) {
// this is where I want to write: stats.text = "\(procent)"
// however I can't, because it doesn't register the variable "procent" because it is in another class.
You can either make a global store that stores the values for you
struct Store {
static var valueOne:Int?
}
and then in your view controllers you can set those values
Store.valueOne = 1
Other option would be to send those integers to the next view controller in your
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let destinationController = segue.destinationViewController as? SecondController {
destinationController.valueOne = valueOne
}
}

Updating a integer as a label in swift

I want to change the number value of a label by pressing a button. I used to get errors saying you can't put a number in a string, so, I did string(variable). It now displays the basic number, 1, but when I click it, it doesn't update!
Here is how I set up the variable:
First, I set up the button, to IBAction. Here is the code inside of it:
#IBOutlet weak var NumberOfExploits: UILabel!
#IBAction func exploiter(sender: AnyObject) {
var hacks = 0
hacks += 1
NumberOfExploits.text = String(hacks)
}
Can someone help be find out how to get it to change numbers?
First:
let is used for constants, these can not be changed.
var is used for variables.
Second:
Doing plus one is done with += 1 or with = myVariable + 1
var myVariable = 1
myVariable += 1
label.text = string(myVariable)
It is important to understand that your variables only live as long as the enclosing class or function is alive. So when you declare a variable, constant inside a function (using var let is a declaration) it will be be gone when the function is complete. A UIViewcontroller is there for as long as you want it to be. So declare things in there that you will need later.
import UIKit
// things that live here are at the "global level"
// this is a viewcontroller. It is a page in your app.
class ViewController: UIViewController {
// things that live here are at the "class level"
var myClassCounter : Int = 0
// button in interfacebuilder that is connected through an outlet.
#IBOutlet weak var myButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// this is a function that gets called when the view is loaded
}
override func viewDidAppear(animated: Bool) {
// this is a function that gets called when the view appeared
}
// button function from interface builder
#IBAction func myButtonIsTouched(sender: AnyObject) {
// this will be destroyed when the function is done
var myFunctionCounter = 0
myFunctionCounter += 1
// this will be stored at class level
myClassCounter += 1
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You can also just do
label.text = "\\(variable)"
which will display the number as string.
Most important declare the variable within the class but outside any function
var variable = 1
then write the IBAction function this way
#IBAction func pressButton(sender : UIButton)
{
label.text = "\(++variable)"
}
The syntax ++variable increments the variable by one.
The syntax "\(v)" creates a string of anything which is string representable

Swift: label text --> "fatal error: unexpectedly found nil while unwrapping an Optional value"

like it says in the title, i am trying to change label text upon click of a button. Error appears at line self.playerChoice.text = "You: Rock"
import UIKit
class ViewController: UIViewController {
var player : Int = Int()
#IBOutlet weak var readyLabel: UILabel!
#IBAction func noButton(sender: AnyObject) {
exit(0)
}
// ---------------------------------------------------------
#IBOutlet var computerChoice: UILabel!
#IBOutlet var playerChoice: UILabel!
#IBOutlet var score: UILabel!
// Variables -------------------------------------------------
let Rock : String = "Rock"
let Paper : String = "Paper"
let Scissors : String = "Scissors"
//------------------------------------------------------------
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
// ----------------------------------------------------------------
#IBAction func rockButton(rockbut: UIButton) {
player = 0
var ai = arc4random_uniform(3)
self.playerChoice.text = "You: Rock"
}
#IBAction func paperButton(paperbut: UIButton) {
player = 1
var ai = arc4random_uniform(3)
self.playerChoice.text = "You: Paper"
}
#IBAction func scissorsButton(scissorsbut: UIButton) {
player = 2
var ai = arc4random_uniform(3)
self.playerChoice.text = "You: Scissors"
}
}
I ran into this problem and it turned out that the labels that I was trying to edit didn't exist at the time the code ran.
Turns out I was referencing the same view controller from a parent view and a child container view. The labels I was trying to change were only in the container view but as both views loaded it ran the view controller for both so it tried to find the labels that didn't exist in the parent view and threw the above error.
So the lesson I learned... If a reference to a view object is throwing a NIL..
The View isn't properly mapped to the View Controller.
The object within the view isn't mapped to the referencing IBOutlet.
Or as in my case, there are multiple views connected to the same View Controller and references to view objects in one view are not being found in the other.
Looks like player choice is not initialized.
#IBOutlet var playerChoice: UILabel!
Maybe the connection between the outlet and InterfaceBuilder/Storyboard is lost. Try to connect it again.
I've created a small demo and everything works fine:
Check if the circles at the left side of your IBOutlet are filled. Otherwise the connection is lost.
What fixed this for me (and it gets me everytime, especially when you are new to using storyboards) is to make sure that you are initializing your view controller like so :
slideShowVC = (UIStoryboard(name: "Main",bundle: nil).instantiateViewControllerWithIdentifier("WWPhotoSlideShowVC") as! WWPhotoSlideShowVC)
instead of the stand alone xib way :
slideShowVC = WWSlideShowVC()
Or else all your outlets will be nil na many headaches will soon follow.
I ran into the same issue in Xcode 6.2.
I use individual XIBs instead of storyboards. The problem for me was that with Swift, Xcode does not automatically associate the XIB with the view controller if the names are the same. Hence the IBOutlets for the labels are pointing to nil giving the fatal.
You can change the viewcontroller.xib to be called modulename.viewcontroller.xib so that xcode can associate it with the view controller and the issue goes away.
More options are mentioned on this thread:
Can't Load UIViewController XIB file in Storyboard in Swift
I have tried this code and it working fine for me:
class ViewController: UIViewController {
var player : Int = Int() //Declare this globally
#IBOutlet weak var readyLabel: UILabel!
#IBAction func noButton(sender: AnyObject) {
exit(0)
}
// ---------------------------------------------------------
#IBOutlet var computerChoice: UILabel!
#IBOutlet var playerChoice: UILabel!
#IBOutlet var score: UILabel!
// Variables -------------------------------------------------
let Rock : String = "Rock"
let Paper : String = "Paper"
let Scissors : String = "Scissors"
//------------------------------------------------------------
#IBAction func rockButton(rockbut: UIButton) {
player = 0
var ai = arc4random_uniform(3)
self.playerChoice.text = "You: Rock"
}
#IBAction func paperButton(sender: UIButton) {
player = 1
var ai = arc4random_uniform(3)
self.playerChoice.text = "You: Paper"
}
#IBAction func scissorsButton(sender: UIButton) {
player = 2
var ai = arc4random_uniform(3)
self.playerChoice.text = "You: Scissors"
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var p : String = "Undecided"
if (player == 0) {
var p: String = "Rock"
} else if (player == 1) {
var p: String = "Paper"
} else if (player == 2) {
var p: String = "Scissors"
}
}
}