I have a method which need an Array of Strings for further calculations. For now I set up this array through UserDefaults, because it should store small (3-characters string) amount of data:
func setRow(for currency: Currency, in currencies: [Currency]) {
// initialise array from UserDefaults
var currencyRowsArray = UserDefaults.standard.stringArray(forKey: "currencyRowsArray") ?? [String]()
// calculations with the array (add or remove string object to\from it
if currency.isForConverter {
currencyRowsArray.append(currency.shortName!)
} else {
guard let row = currencyRowsArray.firstIndex(of: currency.shortName!) else { return }
currencyRowsArray.remove(at: row)
currency.rowForConverter = 0
}
for (row, object) in currencyRowsArray.enumerated() {
for currency in currencies {
if object == currency.shortName {
currency.rowForConverter = Int32(row)
}
}
}
// save array back to UserDefaults after calculations
UserDefaults.standard.set(currencyRowsArray, forKey: "currencyRowsArray")
}
But since I have a CoreData implemented also I decided to store it in CoreData rather than UserDefaults. Here is how I tried to implement that:
1.I have entity Currency, so I created an attribute currencyRowsArray: Type - Transformable, Custom Class - [String], Transformer - NSSecureUnarchiveFromData, Optional - YES (because I don't need it to initialize every time a created a Currency object with other attributes)
2.In the setRow method:
let request: NSFetchRequest<Currency> = Currency.fetchRequest()
request.predicate = NSPredicate(format: "currencyRowsArray IN %#", currencyRowsArray)
3.Initialize the empty array to fill it later with fetched Data:
currencyRowsArray = [String]()
4.Fetch the array:
do {
let fetchResult = try context.fetch(request)
currencyRowsArray = fetchedResult as! [String]
} catch {
print(error)
}
5.After calculations save the changes:
do {
try context.save()
} catch {
print(error)
}
Full changed code of the setRow method:
func setRow(for currency: Currency, in currencies: [Currency]) {
var currencyRowsArray = [String]()
let request: NSFetchRequest<Currency> = Currency.fetchRequest()
request.predicate = NSPredicate(format: "currencyRowsArray IN %#", currencyRowsArray)
do {
let fetchResult = try context.fetch(request)
currencyRowsArray = fetchResult as! [String]
} catch {
print(error)
}
if currency.isForConverter {
currencyRowsArray.append(currency.shortName!)
} else {
guard let row = currencyRowsArray.firstIndex(of: currency.shortName!) else { return }
currencyRowsArray.remove(at: row)
currency.rowForConverter = 0
}
for (row, object) in currencyRowsArray.enumerated() {
for currency in currencies {
if object == currency.shortName {
currency.rowForConverter = Int32(row)
}
}
}
do {
try context.save()
} catch {
print(error)
}
}
But every time the array loads as empty and when I make change, array doesn't add or remove items in it. What I did wrong?
In my App, I have only one language which is Hebrew. I have changed language on Appdelegate in didfinish launch. Now I have only one issue, On app first time launch did not change language and UIView appearance(LTR) When I run second time it have changed whole app language in Hebrew and UIView. I need language change on first time. I have checked too many answers but it has not working. Please let me know if anything for me.
import Foundation
import UIKit
class LocalizationSystem:NSObject {
var bundle: Bundle!
class var sharedInstance: LocalizationSystem {
struct Singleton {
static let instance: LocalizationSystem = LocalizationSystem()
}
return Singleton.instance
}
override init() {
super.init()
bundle = Bundle.main
}
func localizedStringForKey(key:String, comment:String) -> String {
return bundle.localizedString(forKey: key, value: comment, table: nil)
}
func localizedImagePathForImg(imagename:String, type:String) -> String {
guard let imagePath = bundle.path(forResource: imagename, ofType: type) else {
return ""
}
return imagePath
}
//MARK:- setLanguage
// Sets the desired language of the ones you have.
// If this function is not called it will use the default OS language.
// If the language does not exists y returns the default OS language.
func setLanguage(languageCode:String) {
var appleLanguages = UserDefaults.standard.object(forKey: "AppleLanguages") as! [String]
appleLanguages.remove(at: 0)
appleLanguages.insert(languageCode, at: 0)
UserDefaults.standard.set(appleLanguages, forKey: "AppleLanguages")
UserDefaults.standard.set(languageCode, forKey: "languageCode")
UserDefaults.standard.synchronize() //needs restrat
if let languageDirectoryPath = Bundle.main.path(forResource: languageCode, ofType: "lproj") {
bundle = Bundle.init(path: languageDirectoryPath)
} else {
resetLocalization()
}
}
//MARK:- resetLocalization
//Resets the localization system, so it uses the OS default language.
func resetLocalization() {
bundle = Bundle.main
}
//MARK:- getLanguage
// Just gets the current setted up language.
func getLanguage() -> String {
let appleLanguages = UserDefaults.standard.object(forKey: "AppleLanguages") as! [String]
let preferredLanguage = appleLanguages[0]
if preferredLanguage.contains("-") {
let array = preferredLanguage.components(separatedBy: "-")
return array[0]
}
return preferredLanguage
}
}
// Calling in Appdelegate
LocalizationSystem.sharedInstance.setLanguage(languageCode: "he")
UIView.appearance().semanticContentAttribute = .forceRightToLeft
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)
}
in my app while i start my app and i fetch data from coredata. its not giving me data.
but if i not closed my app and save some data in database and without close my app if i fetch data its giving me a data.
and when i close my app. next time again its not giving me data.
Here is my code
self.FetchAllLocalData({ (Available) in
if (Available == "0")
{
for ValueToSave in detailArray!
{
let entity = NSEntityDescription.insertNewObjectForEntityForName("RxOrder", inManagedObjectContext: moc)
print(ValueToSave.id!)
var medicinetype : String = ""
let Id : String = ValueToSave.id!.description
let isRx : String = ValueToSave.isRxMedicine!.description
print(ValueToSave.medicineTypeId)
if (ValueToSave.medicineTypeId != nil)
{
medicinetype = ValueToSave.medicineTypeId!
}
else
{
medicinetype = "0"
}
let medicineName : String = ValueToSave.name!
let orderId : String = ValueToSave.orderId!.description
let price : String = "0"
let quantity : String = ValueToSave.quentity!.description
let strength : String = ValueToSave.strength!
entity.setValue(Id, forKey: "medicineId")
entity.setValue(isRx, forKey: "isRxMedicine")
entity.setValue(medicinetype, forKey: "medicineType")
entity.setValue(medicineName, forKey: "productName")
entity.setValue(self.order_id_RX_Medicine!, forKey: "OrderId")
entity.setValue(price, forKey: "price")
entity.setValue(quantity, forKey: "quantity")
entity.setValue(strength, forKey: "strength")
do{
try moc.save()
}
catch {
fatalError("failed To Save Content\(error)")
}
}
and this one for fetching
func FetchAllLocalData(completion : (Available : String)-> Void) {
let request : NSFetchRequest = NSFetchRequest(entityName: "RxOrder")
do{
//request.predicate = NSPredicate(format: "orderId == \(order_id_RX_Medicine!)")
let fetchedPerson = try moc.executeFetchRequest(request)
DataAvailable = fetchedPerson as! [NSManagedObject]
print(DataAvailable.count)
if (DataAvailable.count > 0)
{
print(DataAvailable[0].valueForKey("orderId"))
for OldData in DataAvailable {
print(DataAvailable.count)
print(order_id_RX_Medicine)
print(OldData.valueForKey("orderId"))
if (OldData.valueForKey("orderId")! as! String == order_id_RX_Medicine)
{
completion(Available: "1")
}
else
{
completion(Available: "0")
}
}
}
else
{
completion(Available: "0")
}
}
catch
{
completion(Available: "0")
fatalError("Something Went Wrong \(error)")
}
}
First, since you are here and there are print statements in your code I am going to assume you are seeing those fire and you are not getting an error when your application runs.
Therefore, it would be helpful to see your Core Data creation code.
It would also be helpful to see how you get the moc into the creation code. Is the creation code in the AppDelegate or somewhere else?
What type of persistent store are you using?
You must try this in your app delegate :
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
AppDelegate.shared.saveContext()
}
This will save your data before app terminates
How can I use UserDefaults to save/retrieve strings, booleans and other data in Swift?
ref: NSUserdefault objectTypes
Swift 3 and above
Store
UserDefaults.standard.set(true, forKey: "Key") //Bool
UserDefaults.standard.set(1, forKey: "Key") //Integer
UserDefaults.standard.set("TEST", forKey: "Key") //setObject
Retrieve
UserDefaults.standard.bool(forKey: "Key")
UserDefaults.standard.integer(forKey: "Key")
UserDefaults.standard.string(forKey: "Key")
Remove
UserDefaults.standard.removeObject(forKey: "Key")
Remove all Keys
if let appDomain = Bundle.main.bundleIdentifier {
UserDefaults.standard.removePersistentDomain(forName: appDomain)
}
Swift 2 and below
Store
NSUserDefaults.standardUserDefaults().setObject(newValue, forKey: "yourkey")
NSUserDefaults.standardUserDefaults().synchronize()
Retrieve
var returnValue: [NSString]? = NSUserDefaults.standardUserDefaults().objectForKey("yourkey") as? [NSString]
Remove
NSUserDefaults.standardUserDefaults().removeObjectForKey("yourkey")
Register
registerDefaults: adds the registrationDictionary to the last item in every search list. This means that after NSUserDefaults has looked for a value in every other valid location, it will look in registered defaults, making them useful as a "fallback" value. Registered defaults are never stored between runs of an application, and are visible only to the application that registers them.
Default values from Defaults Configuration Files will automatically be registered.
for example detect the app from launch , create the struct for save launch
struct DetectLaunch {
static let keyforLaunch = "validateFirstlunch"
static var isFirst: Bool {
get {
return UserDefaults.standard.bool(forKey: keyforLaunch)
}
set {
UserDefaults.standard.set(newValue, forKey: keyforLaunch)
}
}
}
Register default values on app launch:
UserDefaults.standard.register(defaults: [
DetectLaunch.isFirst: true
])
remove the value on app termination:
func applicationWillTerminate(_ application: UIApplication) {
DetectLaunch.isFirst = false
}
and check the condition as
if DetectLaunch.isFirst {
// app launched from first
}
UserDefaults suite name
another one property suite name, mostly its used for App Groups concept, the example scenario I taken from here :
The use case is that I want to separate my UserDefaults (different business logic may require Userdefaults to be grouped separately) by an identifier just like Android's SharedPreferences. For example, when a user in my app clicks on logout button, I would want to clear his account related defaults but not location of the the device.
let user = UserDefaults(suiteName:"User")
use of userDefaults synchronize, the detail info has added in the duplicate answer.
Best way to use UserDefaults
Steps
Create extension of UserDefaults
Create enum with required Keys to
store in local
Store and retrieve the local data wherever you want
Sample
extension UserDefaults{
//MARK: Check Login
func setLoggedIn(value: Bool) {
set(value, forKey: UserDefaultsKeys.isLoggedIn.rawValue)
//synchronize()
}
func isLoggedIn()-> Bool {
return bool(forKey: UserDefaultsKeys.isLoggedIn.rawValue)
}
//MARK: Save User Data
func setUserID(value: Int){
set(value, forKey: UserDefaultsKeys.userID.rawValue)
//synchronize()
}
//MARK: Retrieve User Data
func getUserID() -> Int{
return integer(forKey: UserDefaultsKeys.userID.rawValue)
}
}
enum for Keys used to store data
enum UserDefaultsKeys : String {
case isLoggedIn
case userID
}
Save in UserDefaults where you want
UserDefaults.standard.setLoggedIn(value: true) // String
UserDefaults.standard.setUserID(value: result.User.id!) // String
Retrieve data anywhere in app
print("ID : \(UserDefaults.standard.getUserID())")
UserDefaults.standard.getUserID()
Remove Values
UserDefaults.standard.removeObject(forKey: UserDefaultsKeys.userID)
This way you can store primitive data in best
Update
You need no use synchronize() to store the values. As #Moritz pointed out the it unnecessary and given the article about it.Check comments for more detail
Swift 4 :
Store
UserDefaults.standard.set(object/value, forKey: "key_name")
Retrive
var returnValue: [datatype]? = UserDefaults.standard.object(forKey: "key_name") as? [datatype]
Remove
UserDefaults.standard.removeObject(forKey:"key_name")
UserDefault+Helper.swift
import UIKit
private enum Defaults: String {
case countryCode = "countryCode"
case userloginId = "userloginid"
}
final class UserDefaultHelper {
static var countryCode: String? {
set{
_set(value: newValue, key: .countryCode)
} get {
return _get(valueForKay: .countryCode) as? String ?? ""
}
}
static var userloginId: String? {
set{
_set(value: newValue, key: .userloginId)
} get {
return _get(valueForKay: .userloginId) as? String ?? ""
}
}
private static func _set(value: Any?, key: Defaults) {
UserDefaults.standard.set(value, forKey: key.rawValue)
}
private static func _get(valueForKay key: Defaults)-> Any? {
return UserDefaults.standard.value(forKey: key.rawValue)
}
static func deleteCountryCode() {
UserDefaults.standard.removeObject(forKey: Defaults.countryCode.rawValue)
}
static func deleteUserLoginId() {
UserDefaults.standard.removeObject(forKey: Defaults.userloginId.rawValue)
}
}
Usage:
Save Value:
UserDefaultHelper.userloginId = data["user_id"] as? String
Fetch Value:
let userloginid = UserDefaultHelper.userloginId
Delete Value:
UserDefaultHelper.deleteUserLoginId()
I would say Anbu's answer perfectly fine but I had to add guard while fetching preferences to make my program doesn't fail
Here is the updated code snip in Swift 5
Storing data in UserDefaults
#IBAction func savePreferenceData(_ sender: Any) {
print("Storing data..")
UserDefaults.standard.set("RDC", forKey: "UserName") //String
UserDefaults.standard.set("TestPass", forKey: "Passowrd") //String
UserDefaults.standard.set(21, forKey: "Age") //Integer
}
Fetching data from UserDefaults
#IBAction func fetchPreferenceData(_ sender: Any) {
print("Fetching data..")
//added guard
guard let uName = UserDefaults.standard.string(forKey: "UserName") else { return }
print("User Name is :"+uName)
print(UserDefaults.standard.integer(forKey: "Age"))
}
//Save
NSUserDefaults.standardUserDefaults().setObject("yourString", forKey: "YourStringKey")
//retrive
let yourStr : AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey("YourStringKey")
You can use NSUserDefaults in swift this way,
#IBAction func writeButton(sender: UIButton)
{
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("defaultvalue", forKey: "userNameKey")
}
#IBAction func readButton(sender: UIButton)
{
let defaults = NSUserDefaults.standardUserDefaults()
let name = defaults.stringForKey("userNameKey")
println(name) //Prints defaultvalue in console
}
Swift 5 and above:
let defaults = UserDefaults.standard
defaults.set(25, forKey: "Age")
let savedInteger = defaults.integer(forKey: "Age")
defaults.set(true, forKey: "UseFaceID")
let savedBoolean = defaults.bool(forKey: "UseFaceID")
defaults.set(CGFloat.pi, forKey: "Pi")
defaults.set("Your Name", forKey: "Name")
defaults.set(Date(), forKey: "LastRun")
let array = ["Hello", "World"]
defaults.set(array, forKey: "SavedArray")
let savedArray = defaults.object(forKey: "SavedArray") as? [String] ?? [String()
let dict = ["Name": "Your", "Country": "YourCountry"]
defaults.set(dict, forKey: "SavedDict")
let savedDictionary = defaults.object(forKey: "SavedDictionary") as? [String: String] ?? [String: String]()
:)
I saved NSDictionary normally and able to get it correctly.
dictForaddress = placemark.addressDictionary! as NSDictionary
let userDefaults = UserDefaults.standard
userDefaults.set(dictForaddress, forKey:Constants.kAddressOfUser)
// For getting data from NSDictionary.
let userDefaults = UserDefaults.standard
let dictAddress = userDefaults.object(forKey: Constants.kAddressOfUser) as! NSDictionary
I have Created my Custom Functions for Store Data in Userdefualts
//******************* REMOVE NSUSER DEFAULT *******************
func removeUserDefault(key:String) {
UserDefaults.standard.removeObject(forKey: key);
}
//******************* SAVE STRING IN USER DEFAULT *******************
func saveInDefault(value:Any,key:String) {
UserDefaults.standard.setValue(value, forKey: key);
UserDefaults.standard.synchronize();
}
//******************* FETCH STRING FROM USER DEFAULT *******************
func fetchString(key:String)->AnyObject {
if (UserDefaults.standard.object(forKey: key) != nil) {
return UserDefaults.standard.value(forKey: key)! as AnyObject;
}
else {
return "" as AnyObject;
}
}
class UserDefaults_FavoriteQuote {
static let key = "appname.favoriteQuote"
static var value: String? {
get {
return UserDefaults.standard.string(forKey: key)
}
set {
if newValue != nil {
UserDefaults.standard.set(newValue, forKey: key)
} else {
UserDefaults.standard.removeObject(forKey: key)
}
}
}
}
In class A, set value for key:
let text = "hai"
UserDefaults.standard.setValue(text, forKey: "textValue")
In class B, get the value for the text using the key which declared in class A and assign it to respective variable which you need:
var valueOfText = UserDefaults.value(forKey: "textValue")
Swift 4,
I have used Enum for handling UserDefaults.
This is just a sample code. You can customize it as per your requirements.
For Storing, Retrieving, Removing.
In this way just add a key for your UserDefaults key to the enum.
Handle values while getting and storing according to dataType and your requirements.
enum UserDefaultsConstant : String {
case AuthToken, FcmToken
static let defaults = UserDefaults.standard
//Store
func setValue(value : Any) {
switch self {
case .AuthToken,.FcmToken:
if let _ = value as? String {
UserDefaults.standard.set(value, forKey: self.rawValue)
}
break
}
UserDefaults.standard.synchronize()
}
//Retrieve
func getValue() -> Any? {
switch self {
case .AuthToken:
if(UserDefaults.standard.value(forKey: UserDefaultsConstant.AuthToken.rawValue) != nil) {
return "Bearer "+(UserDefaults.standard.value(forKey: UserDefaultsConstant.AuthToken.rawValue) as! String)
}
else {
return ""
}
case .FcmToken:
if(UserDefaults.standard.value(forKey: UserDefaultsConstant.FcmToken.rawValue) != nil) {
print(UserDefaults.standard.value(forKey: UserDefaultsConstant.FcmToken.rawValue))
return (UserDefaults.standard.value(forKey: UserDefaultsConstant.FcmToken.rawValue) as! String)
}
else {
return ""
}
}
}
//Remove
func removeValue() {
UserDefaults.standard.removeObject(forKey: self.rawValue)
UserDefaults.standard.synchronize()
}
}
For storing a value in userdefaults,
if let authToken = resp.data?.token {
UserDefaultsConstant.AuthToken.setValue(value: authToken)
}
For retrieving a value from userdefaults,
//As AuthToken value is a string
(UserDefaultsConstant.AuthToken.getValue() as! String)
use UserDefault to store any settings value you want your application to remember between start ups, maybe you want to know ifs its been started before, maybe you want some values the user has set to be remembers so they don't have to be set very time, on Mac windows frames are stored in there for you, maybe you want to control the behaviour of the app, but you don't want it available to end users, you just want to choose just before your release. Be careful what you store in UserDefaults, it's not protected.