How to store and retrieve Dictionary value types in Swift - swift

I was having trouble storing a Dictionary in the NSUserDefaults, and then I had trouble retrieving the values. After a failed search on the web, I finally figured it out and so I hope this helps you with this same issue.

Define your variables for NSUserDefaults, Dictionary and key:
let defaults = NSUserDefaults.standardUserDefaults()
var myDictionary = Dictionary<String, Int>()
let myKey = "Key"
How to save your dictionary:
defaults.setObject(myDictionary, forKey: myKey)
How to retrieve your dictionary:
myDictionary = defaults.dictionaryForKey(myKey) as! Dictionary<String, Int>
NOTE: make sure that your data types are the same as the way you set them up.
*** FYI, this is using Xcode 6.3.2

Related

Swift Userdefaults converting String to __NSCFString

I have code that save a dictionary of [String: Any] in UserDefaults. On retrieval String are changed to __NSCFString. I am using Mixpanel to track events and sends this dictionary as events properties. Now the problem is __NSCFString is not a valid MixpanelType so Mixpanel is discarding my dictionary.
Questions:
Is there a way to get same datatypes that are saved using dictionary in UserDefaults?
Is there a way Mixpanel accepts converted datatypes?
Here is a code I am using
var mixpanelProperties: [String: Any] {
get { defaults.dictionary(forKey: "\(#function)") ?? [:] }
set { defaults.set(newValue, forKey: "\(#function)") }
}
mixpanelProperties = ["a-key": "value for the key"]
let prop = mixpanelProperties
print("Type of: \(String(describing: prop["a-key"]))")
asdad
MacOS and iOS use a variety of different classes to represent strings, which are all compatible. x as? String should just work, no matter what the concrete class of x is. Unless you use code that explicitely checks the class which you shouldn't do.

How would you use .updateValue() to add a sub-dictionary to a UserDefaults dictionary?

Is this proper syntax for this line of code? If not what would be the correct syntax and why so?
UserDefaults.standard.dictionary(forKey: "mainDict")?.updateValue(subDict, forKey: "subDictTitle")
First, you have to store Userdefault dictionary to a temporary dictionary. Then you have to add data to a temporary dictionary.
No need to update the dictionary to Userdefault. When you store Dictionary to the Usedefault with the same key, it will replace the older dictionary to the new one.
UserDefaults.standard.set(YOUR_TEMPORARY_DICTIONARY, forKey: YOUR_KEY_NAME)
The updateValue(_:forKey:) is a mutating instance method for the dictionary, which means that it updates the value of the dictionary. Obviously, In order to mutate an instance, it has to be mutable, which is not the case when calling UserDefaults.standard.dictionary(forKey: "mainDict").
Even if you did:
let myDict = ["k1": "Hello"]
UserDefaults.standard.register(defaults: ["myDict": myDict])
var mutable = UserDefaults.standard.dictionary(forKey: "myDict")!
mutable["k1"] = "HEY"
print(UserDefaults.standard.dictionary(forKey: "myDict")) // Optional(["k1": Hello])
the value of the dictionary set in the user default won't change because simply mutable is a copy of it.
To clarify, it's similar to implementing:
UserDefaults.standard.register(defaults: ["k2": "this is my string"])
UserDefaults.standard.string(forKey: "k2") = "new string"
which generates the error of
Expression is not assignable: function call returns immutable value
So, in order to resolve this issue, what you should do is to set a new value (updated dictionary) to the user defaults with the same key:
var myDict = UserDefaults.standard.dictionary(forKey: "myDict")
myDict?.updateValue("Hey", forKey: "k1")
UserDefaults.standard.set(myDict, forKey: "myDict")

How to access CFDictionary in Swift 3?

I need to read and write some data from CFDictionary instances (to read and update EXIF data in photos). For the life of me, I cannot figure out how to do this in Swift 3. The signature for the call I want is:
func CFDictionaryGetValue(CFDictionary!, UnsafeRawPointer!)
How the heck do I convert my key (a string) to an UnsafeRawPointer so I can pass it to this call?
If you don't have to deal with other Core Foundation functions expecting an CFDictionary, you can simplify it by converting to Swift native Dictionary:
if let dict = cfDict as? [String: AnyObject] {
print(dict["key"])
}
Be careful converting a CFDictionary to a Swift native dictionary. The bridging is actually quite expensive as I just found out in my own code (yay for profiling!), so if it's being called quite a lot (as it was for me) this can become a big issue.
Remember that CFDictionary is toll-free bridged with NSDictionary. So, the fastest thing you can do looks more like this:
let cfDictionary: CFDictionary = <code that returns CFDictionary>
if let someValue = (cfDictionary as NSDictionary)["some key"] as? TargetType {
// do stuff with someValue
}
What about something like:
var key = "myKey"
let value = withUnsafePointer(to: &key){ upKey in
return CFDictionaryGetValue(myCFDictionary, upKey)
}
You can write something like this:
let key = "some key" as NSString
if let rawResult = CFDictionaryGetValue(cfDictionary, Unmanaged.passUnretained(key).toOpaque()) {
let result = Unmanaged<AnyObject>.fromOpaque(rawResult).takeUnretainedValue()
print(result)
}
But I guess you would not like to write such thing at any time you retrieve some data from that CFDictionary. You better convert it to Swift Dictionary as suggested in Code Different's answer.

Dictionary saved to NSUserDefaults always returns nil

I'm trying to save a dictionary to NSUserDefaults using the setObject() function but when I use the objectForKey() function to retrieve the dictionary it returns nil. Why is this happening?
var data = NSUserDefaults.standardUserDefaults();
var scoreboard = [Int : String]()
let scores = "scoresKey"
scoreboard[3] = "spencer"
scoreboard[6] = "brooke"
scoreboard[11] = "jason"
data.setObject(scoreboard, forKey: scores)
data.objectForKey(scores) // Returns nil
The first problem was that it's not possible to use NSUserDefaults in a Playground.
See: https://stackoverflow.com/a/31210205/3498950
A second problem is found when the code above runs in a normal iOS project. It throws an NSInvalidArgumentException since the dictionary was a non-property list object because the keys needed to be of type String.
Although NSDictionary and CFDictionary objects allow their keys to be
objects of any type, if the keys are not string objects, the
collections are not property-list objects.
See: "What is a Property List?" in the Apple Docs

Why I can not use SetValue for Dictionary?

Hello Everyone I am new in swift and In my app I declare a dictionary like this :
var imageDict : Dictionary<String, String> = [:]
and I want to set values for that dictionary like this :
imageDict.setValue(NSStringFromCGPoint(frame), forKey: NSString.stringWithString("/(tagValue)"));
But I got error like this :
Dictonary <String, String> does not have a member named 'setValue'
This question is from my previous question and can enybody explain my why I can not set value for that dictionar and can enybody tell me any other way to do that?
Thanks In advance.
Swift dictionary does not have method like setValue:forKey:. Only NSMutableDictionary has such methods. If you wish to assign value for key in swift, you should use subscripting. Here is the correct way to do it, if you wish to do it with swift dictionary.
var imageDict:[String: String] = [:]
imageDict["\(tagValue)"] = NSStringFromCGRect(frame)
Or if you wish to use NSMutableDictionary then, it looks like this,
var imageDict = NSMutableDictionary()
imageDict.setObject(NSStringFromCGRect(frame), forKey: "\(tagValue)")
I guess you need to use NSMutableDictionary.