Having problems with saving and loading in Swift 3.0 iOS 10 - ios

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

Related

Trying to add multiple Uitextfields as integers [duplicate]

This question already has answers here:
Sum of 3 UITextField? [closed]
(2 answers)
Closed 4 years ago.
I am having trouble turning my Uitextfields into integers. I am trying to add them to get a total score for hole 2 and hole 3? Do you all have any ideas? I have tried Int(hole.text) and many other variations, but i keep getting errors.
//
// ViewController.swift
// Savetext5
//
// Created by Brendan Berkowitz on 1/31/19.
// Copyright © 2019 Brendan Berkowitz. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
//hole one
#IBOutlet weak var playername: UITextField!
#IBAction func saveButton(_ sender: Any) {
UserDefaults.standard.set(playername.text, forKey: "playonename")}
#IBAction func deleteButton(_ sender: Any) {
UserDefaults.standard.removeObject(forKey: "playonename")}
// hole 2
#IBOutlet weak var holetwo: UITextField!
#IBAction func saveButton2(_ sender: Any) {
UserDefaults.standard.set(holetwo.text, forKey: "holetwo")}
#IBAction func deleteButton2(_ sender: Any) {
UserDefaults.standard.removeObject(forKey: "holetwo")}
// hole 3
#IBOutlet weak var holethree: UITextField!
#IBAction func savebutton3(_ sender: Any) {UserDefaults.standard.set(holethree.text, forKey: "holethree")}
#IBAction func deletebutton3(_ sender: Any) {UserDefaults.standard.removeObject(forKey: "holethree")}
override func viewDidLoad() {
super.viewDidLoad()
//hole one
let savedName = UserDefaults.standard.object(forKey: "playonename")
if let playeronename = savedName as? String {
playername.text = playeronename
}
// Hole two
let savedholetwoname = UserDefaults.standard.object(forKey: "holetwo")
if let holetwoname = savedholetwoname as? String {
holetwo.text = holetwoname
}
// hole three
let savedholethreename = UserDefaults.standard.object(forKey: "holethree")
if let holethreename = savedholethreename as? String {
holethree.text = holethreename
}
}
}
There are many solutions you can choose. But before you are going to convert the textfield's text to Int, you should do some checking and handling
e.g Is text empty? Is the text's format valid?
// define utility function
extension UITextField {
var textToInt: Int {
// return 0 as default value
return Int(text ?? "0") ?? 0
}
}
class ViewController: UIViewController {
func totalScore() -> Int {
return holetwo.textToInt + holethreename.textToInt
}
}
let textFieldOne = UITextField()
let textFieldTwo = UITextField()
let sum: Int = {
if let scoreOne = Int(textFieldOne.text ?? "0"), let scoreTwo = Int(textFieldTwo.text ?? "0") {
return scoreOne + scoreTwo
}
return 0
}()

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

Userdefaults to save switch state

I Have a switch that when turned to "on" will put the music and when the switch is set to "off" the music will resume playing. My problem is that when i leave the view controller the switch will appear as "off" when it is switch "on". The code for my switch is below, I'm not sure what to write in order for the app to remember the switch state, please help.
//
// SecondViewController.swift
// Urban Sphere
//
// Created by Oren Edrich on 9/11/16.
// Copyright © 2016 Oren Edrich. All rights reserved.
//
import Foundation
import UIKit
import SpriteKit
import AVFoundation
var bombSoundEffect: AVAudioPlayer!
var Ghost = SKSpriteNode()
class SecondViewController: UIViewController {
var sw = false
#IBOutlet var mySwitch: UISwitch!
#IBAction func switchpressed(_ sender: AnyObject) {
if mySwitch.isOn{
if bombSoundEffect != nil {
bombSoundEffect.stop()
bombSoundEffect = nil
}
}
else{
let path = Bundle.main.path(forResource: "newmusic.wav", ofType:nil)!
let url = URL(fileURLWithPath: path)
do {
let sound = try AVAudioPlayer(contentsOf: url)
bombSoundEffect = sound
sound.numberOfLoops = -1
sound.play()
} catch {
// couldn't load file :(
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
}
I found the correct answer and decided to post it incase anyone has the same question.
#IBAction func saveSwitchState(sender: AnyObject) {
var defaults = NSUserDefaults.standardUserDefaults()
if bluetoothSwitch.on {
defaults.setBool(true, forKey: "SwitchState")
} else {
defaults.setBool(false, forKey: "SwitchState")
}
}
and...
override func viewDidLoad() {
super.viewDidLoad()
var defaults = NSUserDefaults.standardUserDefaults()
if (defaults.objectForKey("SwitchState") != nil) {
bluetoothSwitch.on = defaults.boolForKey("SwitchState")
}
}
You want know where to insert the code , I guess.
updata
updata2
Then you can run directly. If it's useful , please UP this answer.
import Foundation
import UIKit
import SpriteKit
import AVFoundation
class SecondViewController: UIViewController {
static let bombSoundEffect = {()->(AVAudioPlayer) in
let path = Bundle.main.path(forResource: "newmusic.wav", ofType:nil)!
let url = URL(fileURLWithPath: path)
return try! AVAudioPlayer(contentsOf: url)
}()
var sw = false
var Ghost = SKSpriteNode()
#IBOutlet var mySwitch: UISwitch!
#IBAction func switchpressed() {
if mySwitch.isOn{
SecondViewController.bombSoundEffect.play()
}else{
SecondViewController.bombSoundEffect.stop()
}
//************* save status *************
UserDefaults.standard.set(mySwitch.isOn, forKey: "SwitchStatus");
}
override func viewDidLoad() {
super.viewDidLoad()
mySwitch.addTarget(self, action: #selector(switchpressed), for: .valueChanged)
//************* load status *************
mySwitch.isOn = UserDefaults.standard.bool(forKey: "SwitchStatus");
switchpressed()
}
}
I have a similar situation to yours, and I just use UserDefaults. Here's a step-by-step guide on how to do it.
Create a variable like the following example. This will set the default setting and store the state of the check box for use later:
var musicSetting = UserDefaults().string(forKey: "Music") ?? "On"
In your viewDidLoad, add an if statement that will check whether the Check Box should be On or Off, like this:
if musicSetting == "On" {
theNameOfYourSwitch.isOn = false
} else {
theNameOfYourSwitch.isOn = true
}
In the IBAction property for your check box, add an if statement like the following that will save your Setting, depending on what it is:
if theNameOfYourCheckbox.state == NSOnState {
UserDefaults().set("On", forKey: "Music")
} else {
UserDefaults().set("Off", forKey: "Music")
}
Here's a screenshot that might help:
If you want to save the state of Switch in user default, then can use the
native method
UserDefaults.standard.set(_ value: Bool, forKey defaultName: String)
Like this
UserDefaults.standard.set(mySwitch.isOn, forKey: "SwitchStatus");
UserDefaults.standard.synchronize();
While fetching switch status just use
let status = UserDefaults.standard.bool(forKey: "SwitchStatus");
UPDATE :
#IBAction func switchpressed(_ sender: AnyObject) {
UserDefaults.standard.set(mySwitch.isOn, forKey: "SwitchStatus");
if mySwitch.isOn{
if bombSoundEffect != nil {
bombSoundEffect.stop()
bombSoundEffect = nil
}
}
else{
let path = Bundle.main.path(forResource: "newmusic.wav", ofType:nil)!
let url = URL(fileURLWithPath: path)
do {
let sound = try AVAudioPlayer(contentsOf: url)
bombSoundEffect = sound
sound.numberOfLoops = -1
sound.play()
} catch {
// couldn't load file :(
}
}
}
Hope it helps
Happy coding ...

Save score in a game with NSUserdefaults

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

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