NSUserDefault critical coding in ios9 swift? - swift

I am following a tutorial in which I am saving data in a NSUserDefault type having the following code. It has comments but I can't get what's happening over here-
var todoDictionary = NSUserDefaults.standardUserDefaults().dictionaryForKey(ITEMS_KEY) ?? Dictionary() // if todoItems hasn't been set in user defaults, initialize todoDictionary to an empty dictionary using nil-coalescing operator (??)
todoDictionary[item.UUID] = ["deadline": item.deadline, "title": item.title, "UUID": item.UUID] // store NSData representation of todo item in dictionary with UUID as key
NSUserDefaults.standardUserDefaults().setObject(todoDictionary, forKey: ITEMS_KEY)
NSUserDefaults.standardUserDefaults().setObject(todoDictionary, forKey: ITEMS_KEY)
So what's actually happening here can anyone please explain a bit.
What is the ITEMS_KEY doing here ?

Line 1 is retrieving a dictionary from the UserDefaults with key ITEMS_KEY, when that fails, it instantiates an empty Dictionary(). That is what the null-coalescing operator means. ITEMS_KEY is a property you might have set somewhere (a constant).
Line 2 is setting a key-value to the dictionary.
Line 3 is writing the dictionary back to the NSUserDefaults.
Line 4 is double? Not sure if that is right.

Related

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

Add New Key/Value to Dictionary

I have a dictionary of type [String: [String]] and is loaded as blank [ : ].
Is there a way I can append a value to the array associated to a new string key? (i.e. exampleDict["test"].append("test"))
When I print out the dictionary after attempting this, I am returned [ : ], which I believe is because the key does not exist and returns as nil.
Swift has a neat "default" feature for doing things exactly like this.
exampleDict["test", default: []].append("test")
If exampleDict["test"] is nil, the default is returned instead. If you modify the returned default object, that modification goes into the dictionary.
Unfortunately this only works properly for value types, since classes aren't reassigned when they're mutated. Fortunately, Array is a value type, so this will work perfectly here.
You have to use Dictionary.subscript(_:default:).
exampleDict["test", default: []].append("test")

Swift 3: How to read from "Optional(Optional(stringValue))" without optional?

I got the string value from server like this.
let filename = "\(eventList[index]["filename"])"
But I got the value with Optional(Optional(stringValue)).
So I changed that like this.
let filename = "\(eventList[index]["filename"]!)"
Then I got the value with Optional(stringValue).
I can't do any more for this error.
How can I read the filename without any optional?
Use nil-coalescing operator aka double question mark operation. It is used to provide a default value when unwrapping an optional type.
let filename = eventList[index]["filename"] ?? ""
R̶e̶f̶:̶ ̶h̶t̶t̶p̶:̶/̶/̶w̶w̶w̶.̶j̶e̶e̶n̶a̶l̶i̶n̶f̶o̶t̶e̶c̶h̶.̶c̶o̶m̶/̶b̶l̶o̶g̶s̶/̶i̶o̶s̶/̶h̶o̶w̶-̶t̶o̶-̶d̶o̶-̶o̶p̶t̶i̶o̶n̶a̶l̶-̶v̶a̶r̶i̶a̶b̶l̶e̶-̶a̶s̶s̶i̶g̶n̶m̶e̶n̶t̶-̶w̶i̶t̶h̶-̶d̶e̶f̶a̶u̶l̶t̶-̶v̶a̶l̶u̶e̶-̶d̶o̶u̶b̶l̶e̶-̶q̶u̶e̶s̶t̶i̶o̶n̶-̶m̶a̶r̶k̶/̶
https://medium.com/#milanpanchal24/
Use if-let syntax to unwrap optional:
if let fileName = eventList[index]["filename"] {
// use fileName
}
eventList[index] accesses an array item at the given index. The item you are referring seems to be an optional dictionary so before accessing the dictionary item it needs to be unwrapped: eventLists[index]! (assuming it exists and valid of course otherwise it will crash)
then you can access the dictionary require value which is an optional as well:
eventLists[index]!["fileName"]!
assuming your list is valid you will get the desired String object.
I recommend using the safety checks (if-let or other variants) for preventing crashes

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

Swift Spritekit setvalue

In swift with spritekit I want to set a variable of a sprite so I tried to say
p.setValue(value: (String(c)), forKey: "co")
But this gives an error.
So the main question is:
How can i set a key value pair in a sprite to a string
as a key and an int/string as a value?
setValue(_:forKey:) and related methods aren't for associating arbitrary key/value data with an object. They're part of Key-Value Coding, a Cocoa feature that does all sorts of handy things — but unless a class does something special with KVC, all setValue(_:forKey:) does is let you set one of that class's declared properties using a string instead of by directly accessing a property. In other words, the two lines below are equivalent:
node.name = "foo"
node.setValue("foo", forKey: "name")
If you want to associate arbitrary key-value pairs with your sprites—which can be a great way to keep track of entities in your game—use the userData property.
To use setValue:forKey: you need to have (a) a valid key, and (b) a value of the correct type for that key. For example:
mySprite.setValue(UIColor.redColor(), forKey: "co") // error, "co" isn't a valid key
mySprite.setValue("red", forKey: "color") // error, "color" needs a UIColor value
mySprite.setValue(UIColor.redColor(), forKey: "color") // works!
What value and key are you actually using?