Sorry if this is a newbie question, I am very new to iOS & Swift. I have seen already on the internet how to use User Default, but I don't know how to insert it in my project:
#IBOutlet weak var labelScore: UILabel!
var score = 0
let scoreUserDefault = UserDefaults.standard
#IBAction func button(_ sender: Any) {
score += 1
labelScore.text = String(score)
print(score)
}
override func viewDidLoad() {
super.viewDidLoad()
if let score = scoreUserDefault.value(forKey: "best") as? Int {
self.score = score
}
}
My project did not store the score, which I expected it to do.
Welcome to swift
// you should store value at first
// here also is good lesson for that part
https://www.hackingwithswift.com/example-code/system/how-to-save-user-settings-using-userdefaults
#IBOutlet weak var labelScore: UILabel!
var score = 0
let scoreUserDefault = UserDefaults.standard
#IBAction func button(_ sender: Any) {
score += 1
labelScore.text = String(score)
// you should store value sta key
scoreUserDefault.set(score, forKey: "best")
print(score)
}
override func viewDidLoad() {
super.viewDidLoad()
if let score = scoreUserDefault.integer(forKey: "best"){
self.score = score
}
}
Related
Have made a simple incremental game. I want it so that even if I go to a different VC and then return to the game, or reopen the game, it will show the current score. My issue is that if I leave the game, then the score will return back to zero. I do not want that to happen. The score should not be resetting. I've heard I could use UserDefaults but I am not familiar to it at all. If you can explain using code, that would be best. Thanks.
import UIKit
class CookieClickerVC: UIViewController {
#IBOutlet weak var goldLabel: UILabel!
#IBOutlet weak var numberOfGold: UILabel!
#IBOutlet weak var getGoldButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
formatItems()
let defaults = UserDefaults.standard
defaults.set(0, forKey: "goldCount")
}
#IBAction func getGoldClicked(_ sender: Any) {
goldCount += 1
numberOfGold.text = ("\(goldCount)")
}`
also, you may have already figured out, but goldCount is an unresolved identifier. How should I change the code after button is clicked?
Step 1: declare your goldCount variable and set the initial value to 0
Step 2: on viewDidLoad, get the value stored in the UserDefaults and set it to goldCount
Step 3: Also update your label
Step 4: Update the value of goldCount in userDefaults
import UIKit
class CookieClickerVC: UIViewController {
#IBOutlet weak var goldLabel: UILabel!
#IBOutlet weak var numberOfGold: UILabel!
#IBOutlet weak var getGoldButton: UIButton!
//Step1: declare your goldCount variable and set initial value to 0
var goldCount = 0
override func viewDidLoad() {
super.viewDidLoad()
formatItems()
//Step2: on viewDidLoad, get the value stored in the UserDefaults and set it to goldCount
goldCount = UserDefaults.standard.integer(forKey: "goldCount")
//Step3: then also update your label
numberOfGold.text = ("\(goldCount)")
}
#IBAction func getGoldClicked(_ sender: Any) {
goldCount += 1
numberOfGold.text = ("\(goldCount)")
//Step4: update the value of goldCount in userDefaults
UserDefaults.standard.set(goldCount, forKey: "goldCount")
}
}
You can use these funtions to get and set score
class CookieClickerVC: UIViewController {
#IBOutlet weak var goldLabel: UILabel!
#IBOutlet weak var numberOfGold: UILabel!
#IBOutlet weak var getGoldButton: UIButton!
lazy var goldCount : Int = 0 {
didSet {
numberOfGold.text = ("\(goldCount)")
}
}
override func viewDidLoad() {
super.viewDidLoad()
formatItems()
goldCount = getScore()
}
#IBAction func getGoldClicked(_ sender: Any) {
goldCount += 1
savescore(goldCount)
}
// Save and Get methods ..
func saveScore(_ score:Int) {
let defaults = UserDefaults.standard
defaults.set(score, forKey: "goldCount")
// defaults.synchronize() its [unnecessary][1]
}
// defaults.synchronize() its unnecessary
func getScore()-> Int {
let defaults = UserDefaults.standard
return defaults.integer(forKey: "goldCount")
}
}
Try the below
class ViewController: UIViewController {
#IBOutlet weak var numberOfGold: UILabel!
#IBOutlet weak var highScore: UILabel!
//declare your count variable globally
var goldCount : Int = 0
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
//get the highscore and then set it to label
let userHighScore = getUserScore()
highScore.text = "\(userHighScore)"
}
#IBAction func goldButtonClicked(_ sender: Any) {
goldCount += 1
numberOfGold.text = "\(goldCount)"
}
//function to say game finished and store the score in userdefault
//call this function when the gameHasFinished
func gameFinished() {
saveUserScore(goldCount)
}
func saveUserScore(_ score:Int){
defaults.set(score, forKey: "goldCount")
}
func getUserScore()-> Int {
return defaults.integer(forKey: "goldCount")
}
}
You can change your viewDidLoad function to check the UserDefaults for the "goldCount" key first, and if it has a value, use it. If not just set the score to 0.
override func viewDidLoad() {
super.viewDidLoad()
formatItems()
let defaults = UserDefaults.standard
if let savedScore = defaults.value(forKey: "goldCount") as? Int {
goldCount = savedScore
} else {
defaults.set(0, forKey: "goldCount")
}
}
You can define "goldCount" as var goldCount: Int = 0 below your IBOutlets.
Also as a further optimization, you can extract the "goldCount" string to use as let goldCountKey: String = "goldCount" and use it like defaults.set(0, forKey: goldCountKey). Avoiding hard-coded strings is a good practice in my opinion, but not that crucial in this case.
To save the new value in every click, add UserDefaults.standard.set(goldCount, forKey: goldCountKey) in getGoldClicked. Another idea here would be to add this in your AppDelegate's willTerminate function to make sure you get your value saved when the application is terminated. Though that will require references to goldCount value there, so no rush.
Hope it helps!
import UIKit
class CookieClickerVC: UIViewController {
#IBOutlet weak var goldLabel: UILabel!
#IBOutlet weak var numberOfGold: UILabel!
#IBOutlet weak var getGoldButton: UIButton!
private var goldCount: Int = Int()
override func viewDidLoad() {
super.viewDidLoad()
formatItems()
}
#IBAction func getGoldClicked(_ sender: Any) {
goldCount += 1
numberOfGold.text = ("\(goldCount)")
UserDefaults.standard.set(goldCount, forKey: "goldCount")
UserDefaults.standard.synchronize()
//To get the count again you can use
print(UserDefaults.standard.integer(forKey: "goldCount")
}
Whenever there is an increment you can save the value of goldCount like this in your UserDefault and I have also added how can you fetch the same value from UserDefault.
This is my code I don't know what I did wrong. All of the problems are in function steve. LebelText is a timer timer label that is segued from another view controller. So i want to take lebetText convert it to a int to subtract 1 from it then reconvert it back to a string to display the number.
This is view Controller a. The texted being segued is lebelText.
import UIKit
class testViewController: UIViewController {
#IBOutlet var lazel: UILabel!
#IBOutlet var plax: UIButton!
#IBOutlet var stopx: UIButton!
var timer = Timer()
var counter = 0.0
var isRunning = false
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let DestViewController : restultViewController = segue.destination as! restultViewController
DestViewController.LebelText = lazel.text!
}
#IBAction func play(_ sender: Any) {
if !isRunning{
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(testViewController.update), userInfo: nil, repeats: true)
}
plax.isEnabled = false
stopx.isEnabled = true
}
#IBAction func stop(_ sender: Any) {
plax.isEnabled = true
stopx.isEnabled = false
timer.invalidate()
isRunning = false
}
func update(){
counter += 0.1
lazel.text = String(format: "1%f", counter)
lazel.text = "\(counter)"
}}
this is view controller b. The goal is to go to take lebelText convert it to a int to subtracted 1 from it. Then convert it back to a string so it can be displayed.
import UIKit
class restultViewController: UIViewController {
#IBOutlet var dxe: UILabel!
var LebelText = String()
let myInt = Int()
override func viewDidLoad() {
super.viewDidLoad()
steve()
}
func steve(){
var eq = LebelText
var intValue = Int(eq)
let vx = intValue! - 1
let ramit = String(vx)
dxe.text = ramit
}
ok so to get rid of the optional and to be sure it all works you should do like
if let intValue = Int(eq) {
vx = intValue - 1
dxe.text = String(vx)
} else {
//do some stuff if you cannot convert eq to Int
}
but I would recommend you to start with some easier tasks, it looks like you did not completely learn basics.
import UIKit
class restultViewController: UIViewController {
#IBOutlet var someLabel: UILabel!
public var myText: String?
override func viewDidLoad() {
super.viewDidLoad()
self.parseData()
}
private func parseData(){
guard let unwrapedText = self.myText else {
//you didn't pass string
return
}
if let myInt = Int(unwrapedText) {
myInt = myInt - 1
self.someLabel.text = String(myInt)
} else {
//you string is not convertable to int
}
}
}
You Can just do this.
import UIKit
class restultViewController: UIViewController {
#IBOutlet var dxe: UILabel!
var LebelText = String()
let myInt = Int()
override func viewDidLoad() {
super.viewDidLoad()
steve()
}
func steve(){
var eq = Int(LebelText.text)
eq = eq - 1
dxe.text = String(eq)
}
I'm really new to the Swift and iOS programming scene and I am trying to learn a bunch of things. For this app, I want to save and load just one integer, but I am having problems, as everything I found on stack overflow and the Internet just doesn't seem to work on Swift 3. The app crashes immediately, it breaks on:
#IBOutlet weak var StaticLabel: UILabel!
It says "Thread 1: breakpoint 3.5" . Any help and tips would be very much appreciated :)
import UIKit
import AVFoundation
var player: AVAudioPlayer?
var number = 0
class ViewController: UIViewController {
#IBOutlet weak var StaticLabel: UILabel!
#IBOutlet weak var NumberLabel: UILabel!
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
Load()
}
func Load()
{
number = defaults.integer(forKey: "Save")
NumberLabel.text = String(number)
}
func playSound()
{
let path = Bundle.main.path(forResource: "RightYouAre.mp3", ofType: nil)
let url = URL(fileURLWithPath: path!)
do {
let sound = try AVAudioPlayer(contentsOf: url)
player = sound
sound.play()
}
catch {
// couldn't load file :(
}
}
#IBAction func Minus(_ sender: AnyObject) {
number = number - 1
NumberLabel.text = String(number)
defaults.set(number, forKey: "Save")
}
#IBAction func Plus(_ sender: UIButton) {
playSound()
number = number + 1
NumberLabel.text = String(number)
defaults.set(number, forKey: "Save")
}
}
your line of code
number = defaults.integer(forKey: "Save")
user defaults integer for key Save is nil, actually this key does not exist at all in the user defaults
before you load this integer from user defaults , it has to be set first
if defaults.object(forKey: "Save") != nil { number = defaults.integer(forKey: "Save") }
this will make sure the object exists in the user defaults before getting it's value
finally your load function should be
func Load()
{
if defaults.object(forKey: "Save") != nil
{
number = defaults.integer(forKey: "Save")
NumberLabel.text = String(number)
}
}
You need to add null handling to the load function as first time there
will be no value for the key "save" in your UserDefaults.
func Load()
{
if let number = defaults.integer(forKey: "Save")
{
self.number = number
NumberLabel.text = String(number)
}
}
I've made this little app "How many fingers" where the user has to guess how many fingers the computer is holding behind it's back. Now I want it to be able to save the users score with NSUserdefaults, but it's not working. Here is how my code looks right now:
//
// ViewController.swift
// How many Fingers?
//
// Created by Kevin Nguyen on 02.05.15.
// Copyright (c) 2015 Kevin Nguyen. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
#IBOutlet var userGuess: UITextField!
#IBOutlet var userScore: UILabel!
#IBOutlet var userTotal: UILabel!
#IBOutlet var result: UILabel!
var score:Int = 0
var totalGames:Int = 0
#IBAction func resetScore(sender: AnyObject) {
score = 0
userScore.text = "0"
}
#IBAction func start(sender: AnyObject) {
var userGuessInt = userGuess.text.toInt()
var fingers = Int(arc4random_uniform(6))
if userGuessInt <= 5 {
if userGuessInt == fingers {
result.text = "Great! You were right!"
score++
totalGames++
userScore.text = "\(score)"
userTotal.text = "\(totalGames)"
println("User score is \(score); total games is \(totalGames)")
NSUserDefaults.standardUserDefaults().setObject(score, forKey: "svScore")
NSUserDefaults.standardUserDefaults().setObject(totalGames, forKey: "svTotalGames")
} else {
result.text = "Try Again!"
println("User score is \(score); total games is \(totalGames)")
totalGames++
userTotal.text = "\(totalGames)"
NSUserDefaults.standardUserDefaults().setObject(score, forKey: "svScore")
NSUserDefaults.standardUserDefaults().setObject(totalGames, forKey: "svTotalGames")
}
} else{
result.text = "Enter a number from 0 up to 5!"
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if score != 0 {
var score:Int = NSUserDefaults.standardUserDefaults().objectForKey("svScore")! as! Int
userScore.text = "\(score)"
}
if totalGames != 0 {
var totalGames:Int = NSUserDefaults.standardUserDefaults().objectForKey("svTotalGames")! as! Int
userTotal.text = "\(totalGames)"
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
When your application starts the score in viewDidLoad is always 0. So you'll never read the saved data (because of your if condition). You should also check it there is data stored before you try to use it.
Change it like that:
override func viewDidLoad() {
super.viewDidLoad()
if (NSUserDefaults.standardUserDefaults().objectForKey("svScore") != nil) {
score = NSUserDefaults.standardUserDefaults().objectForKey("svScore")! as! Int
}
if score != 0 {
userScore.text = "\(score)"
}
if (NSUserDefaults.standardUserDefaults().objectForKey("svTotalGames") != nil) {
totalGames = NSUserDefaults.standardUserDefaults().objectForKey("svTotalGames")! as! Int
}
if totalGames != 0 {
userTotal.text = "\(totalGames)"
}
}
//To Save Highscore
NSUserDefaults.standardUserDefaults().setInteger(highScore, forKey: "highscore")
//To Call For Highscore
var highScore:Int = NSUserDefaults.standardUserDefaults().integerForKey("highscore")
You could create a HighscoreSaver-util class like that:
class HighscoreSaver {
private let defaults = NSUserDefaults.standardUserDefaults()
private let highscoreKey = "highscore-saver-key-item"
private var highscore:Int = 0
private func updateHighscore(score:Int){
highscore += score
if defaults.integerForKey(highscoreKey) < highscore{
defaults.setInteger(highscore, forKey: highscoreKey)
}
}
func add(score scoreToAdd:Int){
updateHighscore(scoreToAdd)
}
func reset(){
defaults.removeObjectForKey(highscoreKey)
}
func currentHighscore() -> Int{
return highscore
}
}
The usage would be like that:
var high = HighscoreSaver()
//Adds scorevalue to current score
high.add(score: yourScoreToAddToCurrent)
//Resets the score to 0
high.reset()
//Gets current score
high.currentHighscore()
This is my code on the view controller with the total score:
import UIKit
var playerName = ""
var totalScore = 0
var bestPlayer = "Taipan"
var highScore = 100
var myNumber: NSInteger = highScore
var myName: NSString = bestPlayer
class StartVC: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBOutlet weak var lblPlayerName: UILabel!
#IBOutlet weak var lblNameScore: UILabel!
#IBOutlet weak var txtPlayerName: UITextField!
#IBAction func btnPlay(sender: UIButton) {
if txtPlayerName.text == "" {
lblPlayerName.text = "Please enter your name!"
} else {
playerName = txtPlayerName.text
performSegueWithIdentifier("StartingStatsVC", sender: self)
}
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
txtPlayerName.resignFirstResponder()
return true
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(animated: Bool) {
NSUserDefaults.standardUserDefaults().setObject(myNumber, forKey: "fixedHighScore")
NSUserDefaults.standardUserDefaults().setObject(myName, forKey: "fixedPlayerName")
NSUserDefaults.standardUserDefaults().synchronize()
var myscore: AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey("fixedHighScore")
var myplayer: AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey("fixedPlayerName")
NSUserDefaults.standardUserDefaults().synchronize()
lblNameScore.text = String(myplayer as NSString) + ": " + String(myscore as NSInteger)
}
}
This is the code in a different view controller which will replace the highscore and bestplayer if the score is higher than the total:
if totalScore > Int(myNumber as NSNumber) {
myNumber = totalScore
myName = playerName
}
Everything works except for saving the highscore and the bestplayer which is the whole point of using NSUserDefaults. Please let me know what to change for it to save correctly when the app is closed then brought up again.
The problem is that you're setting the object of your two user default keys to myNumber and myName every time the view first appears (in viewWillAppear). You should use registerDefaults, to only add those initial values, if there aren't already values in the dictionary,
override func viewWillAppear(animated: Bool) {
let dict = ["fixedHighSCore":myNumber, "fixedPlayerName":myName]
NSUserDefaults.standardUserDefaults().registerDefaults(dict)
NSUserDefaults.standardUserDefaults().synchronize()
var myscore: AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey("fixedHighScore")
var myplayer: AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey("fixedPlayerName")
NSUserDefaults.standardUserDefaults().synchronize()
lblNameScore.text = String(myplayer as NSString) + ": " + String(myscore as NSInteger)
}
You also need to add the new values to the user defaults in your other controller (I don't know if you're already doing that, but just not showing it).
if totalScore > Int(myNumber as NSNumber) {
NSUserDefaults.standardUserDefaults().setObject(totalScore, forKey: "fixedHighScore")
NSUserDefaults.standardUserDefaults().setObject(playerName, forKey: "fixedPlayerName")
NSUserDefaults.standardUserDefaults().synchronize()
}