I am creating a Save button where the user clicks and stores the information using NSUserDefaults. When the user loads the app again, and clicks Show button, all the information stored before should display. For example
Monday User inserts value 5 times: 20 , 30 ,40 ,50 ,60
Tuesday nothing.
Wednesday nothing.
Thursday same user inserts: 30, 20, 50, 80
Friday values are: 40, 20
Now on Saturday when the user click show then the data should display:
20, 30,40,50,60,30,20,50,80,40,20
SO far my coding is:
#IBOutlet weak var dayTB: UITextField!
#IBOutlet weak var numTB: UITextField!
#IBOutlet weak var showLabel: UILabel! // displays all the values stored
var Money = 0
#IBAction func saveBtn(_ sender: Any) {
Money += 1
var MoneyNumberString:String = String(format: "Dollars:%i", Money)
self.showLabel.text = (string: MoneyNumberString)
let defaults: UserDefaults = UserDefaults.standard
defaults.set(MoneyNumberString, forKey: "money")
defaults.synchronize()
}
#IBAction func showbtnact(_ sender: Any) {
let defaults: UserDefaults = UserDefaults.standard
var money = defaults.value(forKey: "money") as? String
showLabel.text! = money!
}
Hope there is a solution for this problem :) Thanks
When you save values, what you need to do is:
var ary_Values = NSMutableArray()
if UserDefaults.standard.value(forKey: "money") != nil
{
let arr = UserDefaults.standard.value(forKey: "money") as! NSArray
for oldObj in arr
{
ary_Values.add(oldObj)
}
ary_Values.add(self.showLabel.text)
}
UserDefaults.standard.set(ary_Values, forKey: "money")
UserDefaults.standard.synchronize()
Related
func applicationDidFinishLaunching(_ application: UIApplication) {
let defaults = UserDefaults.standard
defaults.set(memes, forKey: "HI")
}
var memes = [ViewController.Meme]()
I wrote this code in my AppDelegate and reload the values in the tableview using this code.
override func viewDidLoad() {
let defaults = UserDefaults.standard
let token = defaults.array(forKey: "HI")?.count
print(token ?? -1)
}
But I can't see the array is filling with anything I'm using it wrong?
You seem to have the ordering wrong. In your applicationDidFinishLaunching(_:) you first need to add items to your array and then store it as follows:
var memes = [ViewController.Meme]()
let defaults = UserDefaults.standard
defaults.set(memes, forKeyL "HI")
And then you can read it as you currently are in your view controller
It looks like you saved an empty array.
AppDelegate.swift:
// if (by whether your array is full)
let defaults = UserDefaults.standard
private let memesKey = "memesHI"
defaults.set(memes, forKey: memesKey)
viewDidLoad():
var memes = [ViewController.Meme]()
let defaults = UserDefaults.standard
private let memesViewKey = "memesHI"
let memesArray = [Any]()
memesArray = memes
let token = defaults.array(memesArray, forKey:memesViewKey)?.count
I'm new to swift and trying to figure out the best way to store user defaults. Here are my 3 initial VC classes of my app where i pass data from the on boarding view, to the start your plan view, to the user info (profile view) - which is where i need to store defaults for users. My issue is - the only user default that is storing is "name" and "monthly" pay seems to work as well. But the "daily budget default" and "daily savings default" (which are doubles) don't seem to store and appear on the 3rd screen, (users profile). I am not getting the correct reference.
1st snippet of code is from the on boarding view controller where i collect their info - to keep things short I'm only showing the calculateData IBAction. As of now - this is where i am trying to grab their user defaults.
2nd VC of info is the view directly after on boarding, where the user can review their info - once they press start from this VC- i create an new user object (should i just create an array of new User objects and store it under NSUserDefaults here?)
3rd VC - this is the actual user profile, where i need all of the user defaults to show. I am going to set this as the initial view controller & set up in app delegate, to load this page first if a user has previously done the on boarding screen.
Please and thank you for any help!
import UIKit
class ViewController: UIViewController, UITextFieldDelegate{
#IBAction func calculateDataButtonPressed(_ sender: UIButton) {
customerName = nameTextField.text!
if let payTotal = Double(monthlyAmountTextField.text!){
monthlyEarning = payTotal
}
if let savingsNumber = Double(desiredSavingsTextField.text!){
desiredSavingsAmount = savingsNumber
}
else {
displayLabel.text = "Enter input as so: 1299.39"
}
budgetForEachDay = ((monthlyEarning - desiredSavingsAmount) / 4.0) / 7.0
savingsForEachDay = (desiredSavingsAmount / 4.0) / 7.0
UserDefaults.standard.set(nameTextField.text, forKey: "name")
UserDefaults.standard.set(monthlyAmountTextField.text, forKey: "monthlyPay")
UserDefaults.standard.set(savingsForEachDay, forKey: "dailySavingsDefault")
UserDefaults.standard.set(budgetForEachDay, forKey: "dailyBudgetDefault")
//THE 4 USER DEFAULTS I NEED TO SAVE
Here is the NEXT CLASS THAT THE SEGUE LOADS Too- i create a new User object here - should i perhaps store User Defaults in a newUserObject array instead of how i am trying to go about it ?
import UIKit
class StartYourPlanViewController: UIViewController {
var nameFieldPassedOver : String?
var monthlyEarningPassedOver : Double?
var desiredSavingsPassedOver : Double?
var budgetToSpend : Double = 55.3
var saveEachDay : Double = 55.5
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var monthtlyEarningLabel: UILabel!
#IBOutlet weak var desiredSavingsLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
nameLabel.text = nameFieldPassedOver
monthtlyEarningLabel.text = "\(monthlyEarningPassedOver!)"
monthtlyEarningLabel.isHidden = true
desiredSavingsLabel.text = "\(desiredSavingsPassedOver!)"
desiredSavingsLabel.isHidden = true
}
func makeNewUserObject(){
let newUser = UserInfo(name: nameFieldPassedOver!, iWantToSave : desiredSavingsPassedOver!, monthlyIncome: monthlyEarningPassedOver!, budgetEachDay : budgetToSpend, youSaveEachDay : saveEachDay)
newUser.printUserBio()
}
#IBAction func startPlanButtonPressed(_ sender: UIButton) {
makeNewUserObject()
performSegue(withIdentifier: "GoToYourUserInfoView", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "GoToYourUserInfoView"{
let userInfoVC = segue.destination as! UserInfoViewController
userInfoVC.userNamePassedOver = nameFieldPassedOver
userInfoVC.userDailyBudgetPassedOver = budgetToSpend
userInfoVC.userMonthlyEarningsPassedOver = monthlyEarningPassedOver
userInfoVC.userDesiredSavingsPassedOver = desiredSavingsPassedOver
userInfoVC.userDailySavingsPassedOver = saveEachDay
}
}
}
AND here will end up being my main and initial VC- where i display the users information for them. I need to Set the default values of user defaults so that they appear on this page everytime an existing user opens the app
class UserInfoViewController : ViewController {
var userNamePassedOver : String?
var userDailyBudgetPassedOver : Double?
var userDailySavingsPassedOver : Double?
var userMonthlyEarningsPassedOver : Double?
var userDesiredSavingsPassedOver : Double?
var newAmountPassedBack : Double = 0.0
let monthlyPay = "monthlyPay"
let name = "name"
let dailySavingsDefault = "dailySavingsDefault"
let dailyBudgetDefault = "dailyBudgetDefault"
#IBOutlet weak var dailySavingsNumberLabel: UILabel!
#IBOutlet weak var userNameLabel: UILabel!
#IBOutlet weak var dailySpendingLimitLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
if let name = UserDefaults.standard.value(forKeyPath: name) as? String{
userNameLabel.text = name
}
if let monthlyPay = UserDefaults.standard.value(forKeyPath: monthlyPay) as? String{
userMonthlyEarningsPassedOver = Double(monthlyPay)
}
if let dailySavingsDefault = UserDefaults.standard.value(forKeyPath: dailySavingsDefault) as? String{
dailySavingsNumberLabel.text = dailySavingsDefault
}
if let dailyBudgetDefault = UserDefaults.standard.value(forKeyPath: dailyBudgetDefault) as? String {
dailySpendingLimitLabel.text = dailyBudgetDefault
}
}
Initially, You have to archive the objects into NSData then we can save it to the UserDefault and retrieve it from UserDefault when needed.
Example is shown below:-
1) Save object to UserDefault
let groups = [Group(id: 1, name: "group1", shortname: "g1"), Group(id: 2, name: "group2", shortname: "g2")]
var userDefaults = UserDefaults.standard
let encodedData: Data = NSKeyedArchiver.archivedData(withRootObject: groups)
userDefaults.set(encodedData, forKey: "groups")
userDefaults.synchronize()
2) Retrieve Object from UserDefault
let decoded = userDefaults.object(forKey: "groups") as! Data
let decodedGroups = NSKeyedUnarchiver.unarchiveObject(with: decoded) as! [Group]
When you set the data is userdefault after it you have to synchronise your userdefault so that userdefault saves the pending data. Make sure you won't have any typo mistake with userdefault identifier.
If you want to store structs on UserDefaults:
// Save the selected timeZone on UserDefaults
if let encodedCity = try? JSONEncoder().encode(cityAndTimeZone) {
UserDefaults.standard.set(encodedCity, forKey: "cityAndTimeZone")
}
// To restore struct from UserDefaults
if let decodedData = UserDefaults.standard.object(forKey: "cityAndTimeZone") as? Data {
if let cityAndTimeZone = try? JSONDecoder().decode(CityAndTimeZone.self, from: decodedData) {
timezoneLabel.text = cityAndTimeZone.city
}
}
I want the code to run once a day, but the way I want to accomplish this is by disabling the button after it is clicked and then reenabling when it has been more than 24 hours.
Would the code below be correct to just save the date the user pressed the button?
if distance < radius{
Total_Points += 10
pointsLabel.text = "Total Points: \(Total_Points)"
getPointsOutlet.isEnabled = false
let clickdate = UserDefaults.standard
if var timeList = clickdate.object(forKey: "timeList") as? [Date]{
timeList.append(Date())
clickdate.set(timeList, forKey: "timeList")
} else {
clickdate.set([Date()], forKey: "timeList")
}
clickdate.synchronize()
}
let PointsDefault = UserDefaults.standard
PointsDefault.setValue(Total_Points, forKey: "Total Points")
Your code
let clickdate = UserDefaults.standard
if var timeList = clickdate.object(forKey: "timeList") as? [Date]{
timeList.append(Date())
clickdate.set(timeList, forKey: "timeList")
} else {
clickdate.set([Date()], forKey: "timeList")
}
clickdate.synchronize()
Is fine for adding a date to an array of saved dates. You could pull that out into a separate function:
func addDateToDefaults(date: Date? = nil) {
let defaults = UserDefaults.standard
if date = nil {
date = Date()
}
if var timeList = defaults.object(forKey: "timeList") as? [Date]{
timeList.append(date)
defaults.set(timeList, forKey: "timeList")
} else {
defaults.set([date!], forKey: "timeList")
}
}
Then you could call that from a button action:
#IBAction func buttonClicked(_ sender: UIButton) {
addDateToDefaults()
//The rest of your button action code goes here
}
With the function addDateToDefaults() above, you can pass in a specific date, or leave off the date parameter and it will append the current date to your array of dates.
You can achieve in this way when you tapped on button save the date value using Userdefaults and then inside your ViewDidAppear, ViewDidload and UIApplicationWillEnterForeground notification method put the check to get dateValue from user defaults and then take the difference of current date and last stored date and accordingly enabled your button.
lazy var userDefaults: UserDefaults = {
return UserDefaults.standard
}()
func ViewDidLoad() {
UserDefaults.set(Date(), forKey:"date")
userDefaults.synchronize()
}
func someMethodWhereYouWantToGetValue() {
guard let value = userDefaults.object(forKey: "date") as? Date else
{return}
print(value)
}
I have an app I am making in Xcode 7.2. I have a main menu with a button that has a segue going to a settings view controller. The settings view controller has the following code and every time I get to that view controller it crashes with an EXC_BREAKPOINT error. The funny thing is that this only happens on my iPhone 4 running iOS 7. It does not crash in the iOS Simulator iPhone 6 running iOS 9.
Anyways, here is the code.
//
// SettingsController.swift
// Arbor Hills iOS
//
// Created by Andrew on 11/22/15.
// Copyright © 2015 Arbor Hills Vet. All rights reserved.
//
import UIKit
class SettingsController: UITableViewController {
#IBOutlet weak var username: UITextField!
#IBOutlet weak var password: UITextField!
#IBOutlet weak var notifications: UISwitch!
override func viewDidLoad(){
super.viewDidLoad()
let defaults = NSUserDefaults.standardUserDefaults()
let dusername = defaults.valueForKey("username")!
let dpassword = defaults.valueForKey("password")!
let dnotifications = defaults.valueForKey("notifications")!
username!.text = String(dusername)
password!.text = String(dpassword)
if(dnotifications as! Bool == true){
notifications.setOn(true, animated: true)
}else{
notifications.setOn(false, animated:true)
}
}
#IBAction func saveUsername(sender: AnyObject) {
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(username.text!, forKey: "username")
}
#IBAction func savePassword(sender: AnyObject) {
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(password.text!, forKey: "password")
}
#IBAction func notificationsModified(sender: AnyObject) {
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(notifications.on, forKey: "notifications")
}
}
NSUserDefaults returns nil for an object if no default value is registered. When you unwrap a nil value you'll get an runtime error (crash).
Apple recommends to register a default value for any key as a placeholder until a custom value is saved the first time.
In AppDelegate add in applicationDidFinshLaunching
let defaults = NSUserDefaults.standardUserDefaults()
let defaultValues = ["username" : "", "password" : "", "notifications" : false]
defaults.registerDefaults(defaultValues)
Swift 3+
let defaults = UserDefaults.standard
let defaultValues : [String : Any] = ["username" : "", "password" : "", "notifications" : false]
userDefaults.register(defaults: defaultValues)
That registers empty strings and a boolean false.
Then you can safely retrieve the values
let defaults = NSUserDefaults.standardUserDefaults()
let dusername = defaults.stringForKey("username")!
let dpassword = defaults.stringForKey("password")!
let dnotifications = defaults.boolForKey("notifications")
Swift 3+
let defaults = UserDefaults.standard
let dusername = defaults.string(forKey:"username")!
let dpassword = defaults.string(forKey:"password")!
let dnotifications = defaults.bool(forKey:"notifications")
Use always stringForKey for String values and boolForKey for Bool values.
Never use valueForKey with NSUserDefaults which is a special KVC method.
Then this code could be also simplified:
username!.text = dusername
password!.text = dpassword
notifications.setOn(dnotifications, animated: true)
When writing to user defaults use setBool:forKey for the Bool value, however there is no String equivalent, setObject:forKey is correct.
You should not use valueForKey to fetch objects from NSUserDefaults. Thats a key-value coding method. (See the link on NSKeyValueCoding. you want objectForKey, and you need to check for nil afterwords:
let defaults = NSUserDefaults.standardUserDefaults()
if let dusername = defaults.objectForKey("username") as String
{
//code to use the username
}
else
{
//code to handle the case where there is no username
}
I tried to set up NSUserDefaults last night but an error keeps occurring:
ViewController3:
save data
#IBAction func tappedAddButton(sender: AnyObject) {
var userDefaults:NSUserDefaults = NSUserDefaults.standardUserDefaults()
var exercisesList:NSMutableArray? = userDefaults.objectForKey("exercisesList") as? NSMutableArray
var dataSet:NSMutableDictionary = NSMutableDictionary()
dataSet.setObject(textField.text, forKey: "exercises")
if ((exercisesList) != nil){
var newMutableList:NSMutableArray = NSMutableArray();
for dict:AnyObject in exercisesList!{
newMutableList.addObject(dict as NSDictionary)
}
userDefaults.removeObjectForKey("exercisesList")
newMutableList.addObject(dataSet)
userDefaults.setObject(newMutableList, forKey: "exercisesList")
}else{
userDefaults.removeObjectForKey("exercisesList")
exercisesList = NSMutableArray()
exercisesList!.addObject(dataSet)
userDefaults.setObject(exercisesList, forKey: "exercisesList")
}
userDefaults.synchronize()
self.view.endEditing(true)
textField.text = ""
}
ViewController1:
load data
var exercises:NSMutableArray = NSMutableArray();
...
override func viewDidAppear(animated: Bool) {
var userDefaults:NSUserDefaults = NSUserDefaults.standardUserDefaults()
var exercisesListFromUserDefaults:NSMutableArray? = userDefaults.objectForKey("exercisesList") as? NSMutableArray
if ((exercisesListFromUserDefaults) != nil){
exercises = exercisesListFromUserDefaults!
}
}
While adding some data to the variable "exercises", the pickerView stays empty.
You are setting userDefaults with the key "exercisesList" but attempting to get the data back with a different key ("itemList")