Save score in a game with NSUserdefaults - ios

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()

Related

How to use User Default?

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
}
}

Extracting and managing array elements in swift

The main objective of this code is the ability for a user to highlight/favourite a page in application. I have an array of quotes which is scrolled through by the user on button click. I would like to have it so that when a "favourite" button is clicked (not implemented in code yet). The current element which the user is viewing is extracted (The whole string?) and then somehow marked / sent into another array. This array is then displayed using my own method. I don't know how this could be done. Here's my viewcontroller file.
import UIKit
class DreamViewController: UIViewController {
#IBOutlet var QuoteImage: UIImageView!
#IBOutlet weak var DreamLabel: UILabel!
var counter = 1
var factIndex = 0
let dreamFact = Dream()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
DreamLabel.text = dreamFact.dreamArray[factIndex]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func LeftSwipe() {
factIndex--
var number = dreamFact.dreamArray.count - 1
if (factIndex < 0){
self.factIndex = number
}
DreamLabel.text = dreamFact.dreamArray[factIndex]
if counter == 1 {
counter = 36
} else {
self.counter--
}
QuoteImage.image = UIImage(named: "frame\(counter).jpg")
}
#IBAction func RightSwipe() {
factIndex++
if factIndex >= dreamFact.dreamArray.count {
self.factIndex = 0
}
DreamLabel.text = dreamFact.dreamArray[factIndex]
if counter == 36 {
counter = 1
} else {
self.counter++
}
QuoteImage.image = UIImage(named: "frame\(counter).jpg")
}
}
if any additional information is required please let me now as soon as possible. Thank You!
You can use the factIndex, that you're using to track the current index, to remove the particular "quote" from the dreamArray that the user has favourited. Seeing as the factIndex is correct in tracking the current quote the user is viewing we know that we can use this to extract the right object from the array.
The suggestion below presumes that you create an Array to store your favourite quotes, such as...
var favouriteQuotesArray: [String] = []
func makeQuoteFavourite() {
let currentQuote = dreamFact.dreamArray[factIndex]
favouriteQuotesArray.append(currentQuote)
}

Array element checking in swift

Currently implementing a favourite function to my application which is based on quotes. I would like to perform a check for if the user has already saved an element to an array. If they have, I would change a favour button to unfavour button.
import UIKit
class DreamViewController: UIViewController {
#IBOutlet var liketext: UIButton!
#IBOutlet var QuoteImage: UIImageView!
#IBOutlet weak var DreamLabel: UILabel!
var counter = 1
var factIndex = 0
let dreamFact = Dream()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
DreamLabel.text = dreamFact.dreamArray[factIndex]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func LeftSwipe() {
factIndex--
var number = dreamFact.dreamArray.count - 1
if (factIndex < 0){
self.factIndex = number
}
DreamLabel.text = dreamFact.dreamArray[factIndex]
if counter == 1 {
counter = 36
} else {
self.counter--
}
QuoteImage.image = UIImage(named: "frame\(counter).jpg")
}
#IBAction func RightSwipe() {
factIndex++
if factIndex >= dreamFact.dreamArray.count {
self.factIndex = 0
}
DreamLabel.text = dreamFact.dreamArray[factIndex]
if counter == 36 {
counter = 1
} else {
self.counter++
}
QuoteImage.image = UIImage(named: "frame\(counter).jpg")
}
struct Constants {
static let defaults = NSUserDefaults.standardUserDefaults()
static let fqKey = "FavoriteQuotes"
static let like = "Like"
static let unlike = "Unlike"
}
class DreamViewController {
var favouriteQuotesArray = Constants.defaults.objectForKey(Constants.fqKey) as? [String] ?? [String]() {
didSet {
Constants.defaults.setObject(favouriteQuotesArray, forKey: Constants.fqKey)
}
}
#IBOutlet weak var likeButton: UIButton! {
didSet {
let favourite = dreamArray[factIndex]
if let foundIndex = find(favouriteQuotesArray, favourite) {
likeButton.setTitle(Constants.unlike, forState: .Normal)
}
else {
likeButton.setTitle(Constants.like, forState: .Normal)
}
}
}
#IBAction func likeButtonClicked(sender: UIButton) {
}
}
}
The dependency on upon the text which is unreliable because if the user reopens the app, the element would still be saved instead of starting out with the default unlike. If the element is found in the array. How would I perform a search inside my favouriteQuotesArray if the element exists like:
if elementfound statement {
button.settitle(unlike)
removearrayatindex statement.
} else {
button.settitle(like)
makeQuoteFavourite()
}
How would the array checking statement look like?
P.S If you can please give tips on building the delete class?
Update:
var favouriteQuotesArray: [String] = NSUserDefaults.standardUserDefaults().objectForKey("thekey") as! [String]
func makeQuoteFavourite() {
if favouriteQuotesArray == nil {
favouriteQuotesArray = []
}
let currentQuote = dreamFact.dreamArray[factIndex]
favouriteQuotesArray.append(currentQuote)
NSUserDefaults.standardUserDefaults().setObject(favouriteQuotesArray, forKey: "thekey")
}
#IBAction func likeButton() {
if contains(favouriteQuotesArray, dreamFact.dreamArray[factIndex]) {
liketext.setTitle("Unlike", forState: UIControlState.Normal)
}
Do it this way; some cleaner coding techniques to cut through the rubble included.
The declaration of favouriteQuotesArray is a gold star one liner. Got it all?
import UIKit
struct Constants {
static let defaults = NSUserDefaults.standardUserDefaults()
static let fqKey = "FavoriteQuotes"
static let like = "Like"
static let unlike = "Unlike"
}
class Page2ViewController: UIViewController {
var dreamArray = [String]() // place holder so class compiles
var factIndex = 0 // place holder so class compiles
var favouriteQuotesArray = Constants.defaults.objectForKey(Constants.fqKey) as? [String] ?? [String]() {
didSet {
Constants.defaults.setObject(favouriteQuotesArray, forKey: Constants.fqKey)
}
}
#IBOutlet weak var likeButton: UIButton! {
didSet {
let favourite = dreamArray[factIndex]
if let foundIndex = find(favouriteQuotesArray, favourite) {
likeButton.setTitle(Constants.unlike, forState: .Normal)
}
else {
likeButton.setTitle(Constants.like, forState: .Normal)
}
}
}
#IBAction func likeButtonClicked(sender: UIButton) {
let favourite = dreamArray[factIndex]
if let foundIndex = find(favouriteQuotesArray, favourite) {
sender.setTitle(Constants.like, forState: .Normal)
favouriteQuotesArray.removeAtIndex(foundIndex)
}
else {
sender.setTitle(Constants.unlike, forState: .Normal)
favouriteQuotesArray.append(favourite)
}
}
}
Try this:
let currentQuote = dreamFact.dreamArray[factIndex]
if find(favouriteQuotesArray!, currentQuote) != nil {
//Do something
}
The better and quick way to find out an element in an array is:
if contains(yourFavArray, stringStatement){
//Contains you can write your logic
}
Change your favouriteArray as below:
var favouriteQuotesArray: [String] = NSUserDefaults.standardUserDefaults().objectForKey("thekey") as! [String]
Edited:
if let foundIndex = find(favouriteQuotesArray, dreamFact.dreamArray[factIndex]) {
sender.setTitle(Constants.like, forState: .Normal)
favouriteQuotesArray.removeAtIndex(foundIndex)
}

swift accessing variable from another file

I am a newbie swift programmer, and I have been asked to write an app that allows you to type in a word, and then generates a random Haiku
This is a tabbed application, with two ViewControllers.
(poem) based on that word. So in the FirstViewController I have the data, and I want to display that data in a nice way, in the SecondViewController.
I have all the poem lines and all in the FirstViewController, but I would like to access these variables in the SecondViewController. I have tried creating a function, that does nothing but returning them, and then in the SecondViewController calling that function, but without any result, since the function simply returned nil. Would be pleased if any of you could help
Thank you!
Here is the FirstViewController:
import UIKit
import Foundation
class FirstViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var keyWordTextField: UITextField!
#IBOutlet weak var syllableSlider: UISlider!
#IBOutlet weak var syllableSliderLabel: UILabel!
var syllableSliderValue = 1
#IBOutlet weak var lineOneTextField: UITextField!
#IBOutlet weak var lineTwoTextField: UITextField!
#IBOutlet weak var lineThreeTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
lineOneTextField.text = "Rad 1"
lineTwoTextField.text = "Rad 2"
lineThreeTextField.text = "Rad 3"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func syllableValueChanged(sender: UISlider) {
syllableSliderValue = Int((sender.value))
syllableSliderLabel.text = "Ordet har: \(syllableSliderValue) stavelser"
}
#IBAction func getNewHaiku() {
if keyWordTextField.text != "" {
let keyWord = keyWordTextField.text
let lineOne = generateLine(keyWord: keyWord, syllables: syllableSliderValue, lineSyllableLenght: 5)
let lineTwo = generateLine(keyWord: keyWord, syllables: syllableSliderValue, lineSyllableLenght: 7)
let lineThree = generateLine(keyWord: keyWord, syllables: syllableSliderValue, lineSyllableLenght: 5)
lineOneTextField.text! = lineOne
lineTwoTextField.text! = lineTwo
lineThreeTextField.text! = lineThree
}
}
func generateLine(#keyWord: String, syllables : Int, lineSyllableLenght : Int) -> String {
let oneSyllables = Dict().oneSyllables
let twoSyllables = Dict().twoSyllables
let threeSyllables = Dict().threeSyllables
let fourSyllables = Dict().fourSyllables
let randomOneSyllableWordNumber = Int(arc4random_uniform(UInt32(oneSyllables.count)))
let randomTwoSyllableWordNumber = Int(arc4random_uniform(UInt32(twoSyllables.count)))
let randomThreeSyllableWordNumber = Int(arc4random_uniform(UInt32(threeSyllables.count)))
let randomFourSyllableWordNumber = Int(arc4random_uniform(UInt32(fourSyllables.count)))
var lineArray : [String] = []
var line = ""
lineArray.append(keyWord)
if syllables == 1 {
let randomWordMethod = Int(arc4random_uniform(2))
if randomWordMethod == 0 {
lineArray.append(fourSyllables[randomFourSyllableWordNumber])
} else if randomWordMethod == 1 {
lineArray.append(threeSyllables[randomThreeSyllableWordNumber])
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
} else if randomWordMethod == 2 {
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
lineArray.append(twoSyllables[randomOneSyllableWordNumber])
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
}
} else if syllables == 2 {
let randomWordMethod = Int(arc4random_uniform(2))
if randomWordMethod == 0 {
lineArray.append(twoSyllables[randomOneSyllableWordNumber])
lineArray.append(oneSyllables[randomTwoSyllableWordNumber])
} else if randomWordMethod == 1 {
lineArray.append(threeSyllables[randomThreeSyllableWordNumber])
} else if randomWordMethod == 2 {
lineArray.append(twoSyllables[randomTwoSyllableWordNumber])
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
}
} else if syllables == 3 {
let randomWordMethod = Int(arc4random_uniform(1))
if randomWordMethod == 0 {
lineArray.append(twoSyllables[randomTwoSyllableWordNumber])
} else if randomWordMethod == 1 {
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
}
} else if syllables == 4 {
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
}
if lineSyllableLenght == 7 {
let randomWordMethod = Int(arc4random_uniform(1))
if randomWordMethod == 0 {
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
} else if randomWordMethod == 1 {
lineArray.append(twoSyllables[randomTwoSyllableWordNumber])
}
}
for word in lineArray {
line += " \(word)"
}
line += ","
return line
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
}
func getData() -> (line2: String, line3: String) {
return (lineTwoTextField.text, lineThreeTextField.text)
}
}
Ps, the "Dict" is another file, but only containing words.
The second view controller is just blank.
Or you could make it a global variable so any file can access it.
struct structname {
static var yourvariable = value
}
When calling it, you enter
filename.structname.yourvariable
You need to pass the instances like this in second view controller:
var firstViewController: FirstViewController?
Then in the master instance which knows both:
secondViewController.firstViewController = firstViewController
(e.g. in awakeFromNib) assuming that they are known in the master instance like
let firstViewController = FirstViewController()
let secondViewController = SecondViewController()
Finally in SecondViewController you can access the first:
firstViewController?.generateLine....

NSUserDefaults in Swift won't save my data the way my code currently is. What's my issue?

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()
}

Resources