Saving to User Defaults in Swift - ios

I am currently trying to save an array to the user defaults.
Here is my code:
//where things will be stored
let defaults = NSUserDefaults.standardUserDefaults()
var taskNames = [String]()
var taskPriorities = [Float]()
//this is the function that saves tasks
func saveTask() {
println(taskNames)
println(taskPriorities)
defaults.setObject(taskNames, forKey: "taskName")
defaults.setObject(taskPriorities, forKey: "taskPriorities")
defaults.synchronize()
}
//this is the function that loads tasks
func loadTasks() {
var taskNamesLoad = defaults.dataForKey("taskName")
println(defaults.dataForKey("taskName"))
println(taskNamesLoad)
}
When I call the function to load the data (after saving some data with the other function of course) the output to the Console is nil and there is no data saved in the user defaults. How can I fix this?

You should use arrayForKey or objectForKey instead dataForKey. Because you store the Array object, not NSData.
Like below:
func loadTasks() {
var taskNamesLoad = defaults.arrayForKey("taskName")
println(defaults.arrayForKey("taskName"))
println(taskNamesLoad)
}

If you're going to save to user defaults you need to use plist safe objects. So instead of using Float you need to use NSNumber.

Related

Swift dictionary doesn't want to populate from C Callback function

I'm writing a PDF Parser in Swift and I've reached the point where I get all the font data with a callback function (CGPDFDictionaryApplyFunction), the getFont function is supposed to populate the fonts dictionary in the PDFFontCollection class.
Inside the "getFont" callback function the collection variable is correctly populated - however when the callback is finished the fonts dictionary has still 0 entrys.
class PDFFontCollection{
var fonts: [AnyHashable:Any]!
init(page: CGPDFPage){
fonts = [AnyHashable:Any]()
let fontsdict = self.findFontDictionary(page: page)
if(fontsdict != nil){
CGPDFDictionaryApplyFunction(fontsdict!, self.getFont , &self.fonts)
}
}
private var getFont: CGPDFDictionaryApplierFunction = { (key, object, info) in
var collection = info?.assumingMemoryBound(to: [AnyHashable: Any].self).pointee
var name = String(cString: key, encoding: String.Encoding.ascii)
var dict: CGPDFDictionaryRef?
if (CGPDFObjectGetValue(object, .dictionary, &dict)){
var font = PDFFont.pdfFont(withFontDictionary: dict!)
collection?.updateValue(font!, forKey: name!)
}
}
For whoever may be interested, PeejWeej is right. You need to declare fonts as an NSMutableDictionary in order to be able to populate it, since [AnyHashable:Any] is always passed by reference.

Save Dictionary into NSUserDefaults Swift

I have a Dictionary and i want to save it to NSUserDefaults(or something else so I can have access to my variables after i have terminated the app) , I found an example:
var saved = NSUserDefaults.standardUserDefaults()
let dict = ["Name": "Paul", "Country": "UK"]
saved.setObject(dict, forKey: "SavedDict")
But when i used it to mine Dictionary it didn't work. (maybe because my dictionary it's a little bit different)
My Dictionary is made like this:
var userDictionary = [Int : Event]()
struct Event {
var sensorName: String
var sensorType: String
var sensorSub: String
}
And i add elements like this:
userDictionary[value] = Event(sensorName: "first", sensorType: "Temp", sensorSub: "Third")
And here is what i tried to do so I can store it.
saved.setObject(userDictionary, forKey: "valueDictionary")
And I get this error:
Cannot convert value of type '[Int : SensorsView.Event]' to expected
argument type 'AnyObject?'
To avoid this error I did this:
self.saved.setObject(self.userDictionary as? AnyObject, forKey: "valueDictionary")
But I can't retrieve what i saved
Unfortunately this question didn't help me after some comments i believe that the goal here is to convert my dictionary to Data (or something else) and after i retrieve it i convert it back to Dictionary
Try to convert the data to NSData and then retrieve like so:
/// Save
NSUserDefaults.standardUserDefaults().setObject(NSKeyedArchiver.archivedDataWithRootObject(object), forKey: key)
/// Read
var data = NSUserDefaults.standardUserDefaults().objectForKey(key) as NSData
var object = NSKeyedUnarchiver.unarchiveObjectWithData(data) as [String: String]
What i think is from the link below you will be able to store the Dictionary into NSUserDefaults
Swift NSUserDefaults not saving Dictionary?
or
Saving dictionary into NSUserDefaults may help
I managed to save my custom Dictionary using Realm!
Instead of a struct I use a different class like this:
import RealmSwift
class Sensors : Object {
dynamic var sensorName = ""
dynamic var sensorType = ""
dynamic var sensorSub = ""
}
and then I fill it like this:
var useOfRealm = try! Realm()
var allSensors = useOfRealm.objects(Sensors.self)
var saving = Sensors()
func fillThis() {
try! useOfRealm.write {
saving.sensorName = "something"
saving.sensorType = "something"
saving.sensorSub = "something"
useOfRealm.add(saving)
}
}
Use the function with parameters so you can fill the 'Dictionary' Dynamically.
Use allSensors so you can retrieve everything that you want.

how to save and read dictionary of touples to NSUserDefaults?

I have an dictionary = String: ([(String)], [(Int)], NSDate, Bool, [(String)]) and I attempted to deconstruct it into seperate arrays when then app calls applicationWillTerminate
var codes = [(String)]()
var messages = [[String]]()
var senders = [[Int]]()
var dates = [(NSDate)]()
var bools = [(Bool)]()
var pairs = [[String]]()
for code in self.dictionary.keys {
codes.append(code)
messages.append(self.dictionary[code]!.0)
senders.append(self.dictionary[code]!.1)
dates.append(self.dictionary[code]!.2)
bools.append(self.dictionary[code]!.3)
pairs.append(self.dictionary[code]!.4)
}
self.userDefaultsMessages.setObject(codes, forKey: "userMessagesArrays")
self.userDefaultsSenders.setObject(messages, forKey: "userSentArrays")
self.userDefaultsDates.setObject(senders, forKey: "userDatesArray")
self.userDefaultsDeletedBool.setObject(dates, forKey: "userDeletedArrays")
self.userDefaultsPairs.setObject(bools, forKey: "userPairsArrays")
self.userDefaultsCodeKeys.setObject(pairs, forKey: "userCodesArrays")
self.userDefaultsCodeKeys.synchronize()
self.userDefaultsMessages.synchronize()
self.userDefaultsSenders.synchronize()
self.userDefaultsDates.synchronize()
self.userDefaultsDeletedBool.synchronize()
self.userDefaultsPairs.synchronize()
and then I attempt to pull it all back together when the app calls applicationDidBecomeActive
//read
if let savedCodesArray : AnyObject? = self.userDefaultsCodeKeys.objectForKey("userCodesArrays") {
self.userCodes = savedCodesArray! as! [String]
if let savedMessagesArray : AnyObject? = self.userDefaultsCodeKeys.objectForKey("userMessagesArrays") {
self.Usermessages = savedMessagesArray! as! [[String]]
if let savedSendersArray : AnyObject? = self.userDefaultsCodeKeys.objectForKey("userSentArrays") {
self.Usersenders = savedSendersArray! as! [[Int]]
if let savedDatesArray : AnyObject? = self.userDefaultsCodeKeys.objectForKey("userDatesArray") {
self.Userdates = savedDatesArray! as! [NSDate]
if let savedBools : AnyObject? = self.userDefaultsCodeKeys.objectForKey("userDeletedArrays") {
self.Userbools = savedBools! as! [Bool]
if let savedPairs : AnyObject? = self.userDefaultsCodeKeys.objectForKey("userPairsArrays") {
self.Userpairs = savedPairs! as! [[String]]
var indexPath: Int = 0
for code in self.userCodes {
self.dictionary[code]! = [self.Usermessages[indexPath], self.Usermessages[indexPath], self.Userdates[indexPath], self.Userbools[indexPath], self.Userpairs[indexPath]]
}
}
}
}
}
}
}
I am fairly new to iOS development and could use help, how would i save the single dictionary = String: ([(String)], [(Int)], NSDate, Bool, [(String)]) to NSUserDefaults and then later read it.. the documentation was not very helpful since it only worked with simple dictionaries
the code looks incredibly cumbersome so I know I can't be doing it right. It should be a simple solution since I only have one variable to save to NSUserDefaults.
Short answer: You can't.
NSUserDefaults will only record "property list objects" (dictionaries, arrays, strings, numbers (integer and float), dates, binary data, and Boolean values).
You can't save any other types of data into NSUserDefaults, or into a property list. The only solution is to convert other data types into those types.
Tuples are not one of those types, so they can't be saved into user defaults.
First, your interaction with NSUserDefaults is completely wrong. You only need to interact with the shared NSUserDefaults.sharedUserDefaults() instance, not create separate instances, which seems to be what you're doing (i.e. userDefaultsMessages, userDefaultsSenders, etc.).
Second, you don't need to call synchronize() at all. There are very few conditions under which you need to call it manually, and this isn't one of them.
Third, the easiest way to store a particular tuple in NSUserDefaults is to convert it into an Array (or NSArray) and store the result. Of course, this assumes that the tuple contains only types that can be serialized, which your example seems to contain. Unfortunately there's no general solution to this, but creating an array from a tuple is straight forward, as you can just map the tuple indices to array indices.
Finally, such large tuples are usually the result of poor design somewhere along the line. Perhaps refactoring would help resolve your storage issue?

Passing an object between controller Swift

I have a storyboard which start with a login page. And I have a User class like this
class User {
// Properties
var firmCode : String
var firmId : String
var userId : String
// Default Initializer
init() {
self.firmCode = ""
self.firmId = ""
self.userId = ""
}
// Defult Initializer with prams
init(firmCode: String, firmId: String, userId: String) {
self.firmCode = firmCode
self.firmId = firmId
self.userId = userId
}
}
I am generating some values in login page, and I can create my User object with these values.
Now I want to make this object global and use this user object in all scene.
How to pass this object to other scenes? For example I want to pass this values with my object to an embed static table view controller like this
Note: Does it matter, the embed controller has a tab bar controller? I guess I need to use my delegate file?
EDIT:
Now I have created my global object like this:
// test value
let firmId = "Company Id"
// Creating user object without user class declaration
NSUserDefaults.standardUserDefaults().setObject(firmId, forKey: "testFirmId")
And trying to get my object like this:
// Creating user variable in other scene by globally
let getValue : AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey("testFirmId")
// checking
println(getValue!)
AND done, return my value on termanal. All work until here.
But now the value return to me as AnyObject, I need the convert it String to apply like this:
someLabel.text = getValue!
You can use NSUserDefaults for that like you can store your object this way:
NSUserDefaults.standardUserDefaults().setObject(YourObject, forKey: "YouKey")
After that you can access it in any scene like:
let yourObject: AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey("YouKey")
Hope It will help you.
EDIT:
NSUserDefaults is limited in the types it can handle: NSData, NSString, NSNumber, NSDate, NSArray, and NSDictionary. Thus no Swift objects or structs can be saved.
From the Apple NSUserDefaults Docs:
A default object must be a property list, that is, an instance of (or
for collections a combination of instances of): NSData, NSString,
NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any
other type of object, you should typically archive it to create an
instance of NSData.
And if you are using NSUserDefaults then you can directly store your instance like shown below:
NSUserDefaults.standardUserDefaults().setObject(test, forKey: "firmCode")
NSUserDefaults.standardUserDefaults().setObject(test, forKey: "firmId")
NSUserDefaults.standardUserDefaults().setObject(test, forKey: "userId")
You Don't need model class for that.
var user = User()
self.user.firmCode = 1
//Assign value to other variables
//Save User object in NSUserDefaults as like this
User.saveUserObject(user)
//Function For Save User
class func saveUserObject(user : User){
let userKey = "UserData \(user.userID)"
NSUserDefaults.standardUserDefaults().setObject(data, forKey: userKey)
}
//Get User Object from NSUserDefaults
class func getUserObject(userIDValue : NSNumber) -> User? {
let userKey = "UserData \(userIDValue)"
if let data = NSUserDefaults.standardUserDefaults().objectForKey(userKey) as? NSData {
return data as? User
}
return nil
}

Adding to swift array keeps overwriting last object

I want to continually add values to a global/constant array. The problem is it just keeps overwriting the last value rather than adding it to the the array so I always end up with 2 values
Global array
struct Globals {
struct savedCalculationData {
static var dataArray = ["something here"]
}
}
Saved to array in another class
//code to copy string value...
//Add to global array
var copiedDataArray = Globals.savedCalculationData.dataArray
copiedDataArray.append ("\(copyText)") <--- string value
//Save array to defaults
NSUserDefaults.standardUserDefaults().setObject(copiedDataArray, forKey: "savedDataArray")
NSUserDefaults.standardUserDefaults().synchronize()
You're appending to a copy of the global array, but don't appear to ever set that updated array back, so the global array is not changing.
Assuming you want keep the global data saved whenever you append to it, I would recommend designing your Globals struct to take care of this automatically:
struct Globals {
// Convenience variable for the standard defaults
private static var Defaults: NSUserDefaults { return NSUserDefaults.standardUserDefaults() }
struct SavedCalculationData {
private static let DataArrayKey = "savedDataArray"
static var dataArray: [String] {
get {
return Defaults.objectForKey(DataArrayKey) as? [String] ?? []
}
set {
// This setter is called when the array contents change,
// not just when a new array is set
Defaults.setObject(newValue, forKey: DataArrayKey)
Defaults.synchronize()
}
}
}
}
Then you can update the global data more succinctly:
Globals.SavedCalculationData.dataArray.append(copyText)
Since Array is copied when it's assigned to new variables, you are not modifying Globals.savedCalculationData.dataArray at all.
You should append without copying:
Globals.savedCalculationData.dataArray.append("\(copyText)")
NSUserDefaults.standardUserDefaults().setObject(Globals.savedCalculationData.dataArray, forKey: "savedDataArray")
or write back copiedDataArray to Globals.savedCalculationData.dataArray
var copiedDataArray = Globals.savedCalculationData.dataArray
copiedDataArray.append ("\(copyText)")
Globals.savedCalculationData.dataArray = copiedDataArray
NSUserDefaults.standardUserDefaults().setObject(copiedDataArray, forKey: "savedDataArray")

Resources