Swift - Empty NSMutableDictionary or NSDictionary? Optional - swift

Just curious, in Swift, is it more ideal to initialize an empty NSMutableDictionary variable, NSMutableDictionary = [:], and later re-assign its value to a new dictionary (coming from an API for example),
OR, is it better to declare an optional NSDictionary, NSDictionary? and assign it to a new dictionary?

So with Swift it would technically be best practice to use a Dictionary type. Like this for example:
var dict: Dictionary<String, Int>
If you need the dictionary as a whole to be able to be nil use an optional.

This depends on your needs, do you want it to be nil sometimes? is it nil sometimes?
If an array is always gonna have value, even if it's an empty value, I personally like to Initialize it right away, and not hassle with unwrapping everywhere.
Maybe if you had two arrays, one was normal array, and the second one was a searched result. You might wanna check if searched result is nil first, if it is, show the array1, if it isn't show it instead.
And this is implying you only search "sometimes", thus that array is only sometimes used - so you might as well have that deallocated when not in use, if you aren't using it most of the time.
EDIT: I've been using arrays in my example, but same applies for a dictionary in those situations.
EDIT: In Swift It's best to avoid 'NS' classes, sometimes you have to use them, sure. But Swift's Dictionary does the job.
Example:
var sometimesUselessDict: Dictionary<String, AnyObject>?
var alwaysUsedDictionary = Dictionary<String, AnyObject>()
Cheers

You should make it optional only if you need to be able to distinguish a dictionary that's empty from one that doesn't exist at all. For instance, if you're receiving data from a server, you might want to distinguish between a successful response that returned no data (empty dictionary) and a failed or invalid response (nil).
If that distinction isn't important, I would always go with a non-optional to avoid unnecessary unwrapping.

Related

Dictionary containing an array - Why is unwrapping necessary?

I'm trying to wrap my head around why what feels intuitive is illegal when it comes to a dictionary containing an array in Swift.
Suppose I have:
var arr = [1,2,3,4,5]
var dict = ["a":1, "b":2, "test":arr]
I can easily access the dictionary members like so:
dict["a"]
dict["b"]
dict["test"]
As expected, each of these will return the stored value, including the array for key "test":
[1,2,3,4,5]
My intuitive reaction to this based on other languages is that this should be legal:
dict["test"][2]
Which I would expect to return 3. Of course, this doesn't work in Swift. After lots of tinkering I realize that this is the proper way to do this:
dict["test"]!.objectAtIndex(2)
Realizing this, I return to my intuitive approach and say, "Well then, this should work too:"
dict["test"]![2]
Which it does... What I don't really get is why the unwrap isn't implied by the array dereference. What am I missing in the way that Swift "thinks?"
All dictionary lookups in Swift return Optional variables.
Why? Because the key you are looking up might not exist. If the key doesn't exist, the dictionary returns nil. Since nil can be returned, the lookup type has to be an Optional.
Because the dictionary lookup returns an Optional value, you must unwrap it. This can be done in various ways. A safe way to deal with this is to use Optional Chaining combined with Optional Binding:
if let value = dict["test"]?[2] {
print(value)
}
In this case, if "test" is not a valid key, the entire chain dict["test"]?[2] will return nil and the Optional Binding if let will fail so the print will never happen.
If you force unwrap the dictionary access, it will crash if the key does not exist:
dict["test"]![2] // this will crash if "test" is not a valid key
The problem is that Dictionary’s key-based subscript returns an optional – because the key might not be present.
The easiest way to achieve your goal is via optional chaining. This compiles:
dict["test"]?[2]
Note, though, that the result will still be optional (i.e. if there were no key test, then you could get nil back and the second subscript will not be run). So you may still have to unwrap it later. But it differs from ! in that if the value isn’t present your program won’t crash, but rather just evaluate nil for the optional result.
See here for a long list of ways to handle optionals, or here for a bit more background on optionals.
In the Objective-C world, it has potential crash if you are trying to access 3 by dict[#"test"][2]. What if dict[#"test"] is nil or the array you get from dict[#"test"] has two elements only? Of course, you already knew the data is just like that. Then, it has no problem at all.
What if the data is fetched from the backend and it has some problems with it? This will still go through the compiler but the application crashes at runtime. Users are not programmers and they only know: The app crashes. Probably, they don't want to use it anymore. So, the bottom line is: No Crashes at all.
Swift introduces a type called Optional Type which means value might be missing so that the codes are safe at runtime. Inside the Swift, it's actually trying to implement an if-else to examine whether data is missing.
For your case, I will separate two parts:
Part 1: dict["test"]! is telling compiler to ignore if-else statement and return the value no matter what. Instead, dict["test"]? will return nil if the value if missing. The terminology is Explicit Unwrapping
Part 2: dict["test"]?[2] has potential crash. What if dict["test"]? returns a valid array and it only has two element? This way to store the data is the same using dict[#"test"][2] in Objective-C. That's why it has something called Optional Type Unwrapping. It will only go the if branch when valid data is there. The safest way:
if let element = dict["test"]?[2] {
// do your stuff
}

Retriving values from core data to text fields

When I retrieve a value from core data, it is displaying with prefix "Optional" on the story board. How to avoid showing "Optional" in front of the retrieved value?
Here is the line of code:
schoolYearStartDateText.text = String(newRateMaster.schoolYearStartDate)
value entered - 01/01/11
Value displayed on debugger and Storyboard:
Optional(0011-01-01 04:56:02 +0000)
With NSSet this gets worse. Value prefixed with Optional and multiple levels of parenthesis!
This is really a question about Swift optionals, and is nothing to do with Core Data. "Optional" shows up because you're using an optional variable. It's optional because it just might be nil, and that's how Swift handles that situation.
Using "!" will unwrap it but isn't really safe. If the value is nil and you're using "!", your app will crash.
You should probably use something like:
schoolYearStartDateText.text = String(newRateMaster.schoolYearStartDate) ?? ""
That will unwrap a non-nil optional safely, and use an empty string if the result is nil. And, you should read up on Swift Optionals to better understand what's going on.

argument for generic parameter could not be inferred

I'm trying to save an array with NSUserDefaults and then load the array, but I get the error "argument for generic parameter could not be inferred." Is there anything I am doing wrong? No one seems to be having this problem in swift, so I can't find any solutions.
IBAction func loadData(sender: AnyObject) {
if let testCompositeArray = defaults.objectForKey("testScoreSATArray") as? Array {
self.showDataLabel.text = defaults.objectForKey("testScoreSATArray") as Array
}
}
The reason you received your original error is that in Swift, Array is a generic container that holds values of a specific type. So you can have an Array<Int> that holds integers, or an Array<String> that holds strings. But you can’t have just an Array. The type of the thing the array contains is the generic parameter, and Swift is complaining because it can’t figure out what that type should be. Sometimes it can infer that type from the context of the code around it, but not always, as in this case.
You can resolve the problem by giving the type of the thing you are storing:
IBAction func loadData(sender: AnyObject) {
if let testCompositeArray = defaults.objectForKey("testScoreSATArray") as? Array<Int> {
self.showDataLabel.text = toString(testCompositeArray)
}
}
Instead of writing Array<Int>, you can write the shorter form, [Int]
You can also solve the problem by using NSArray, as you’ve found. Unlike Array, NSArray doesn’t use generics, since it originates in Objective-C which has a different approach to Swift. Instead, NSArray holds only one kind of thing, an AnyObject. This is is a reference that can point to instances of any class.
However, there’s a big downside to using NSArray and AnyObject, which is that every time you use a value they contain, you often have to “cast” the value to a real thing, like an integer or a string. This can be a pain, and worse, sometimes can cause errors when you assume you have one kind of thing when actually you have another. Swift generally encourages you to be more specific about types to avoid errors like this.

How is a return value of AnyObject! different from AnyObject

The NSMetadataItem class in the Cocoa framework under Swift contains the following function:
func valueForAttribute(key: String!) -> AnyObject!
I'm still learning the difference (and details) between forced unwrapping and optional chaining. In the above function, does this mean:
The key parameter must have a value, and
The return value is guaranteed to have a value?
My primary concern is with the exclamation point following the return value - once I have assigned the return value:
var isDownloadedVal = item.valueForAttribute(NSMetadataUbiquitousItemIsDownloadedKey)
Do I need to include an if let block when examining it, or am I guaranteed that it will have a value I can examine safely?
TLDR: Treat Foo! as if it were Foo.
Many Cocoa calls include implicitly unwrapped optionals, and their need for it is very likely the reason the feature even exists. Here's how I recommend thinking about it.
First, let's think about a simpler case that doesn't involve AnyObject. I think UIDevice makes a good example.
class func currentDevice() -> UIDevice!
What's going on here? Well, there is always a currentDevice. If this returned nil that would indicate some kind of deep error in the system. So if we were building this interface in Swift, this would likely just return UIDevice and be done with it. But we need to bridge to Objective-C, which returns UIDevice*. Now that should never be nil, but it syntactically could be nil. Now in ObjC, we typically ignore that fact and don't nil-check here (particularly because nil-messaging is typically safe).
So how would we express this situation in Swift? Well, technically it's an Optional<UIDevice>, and you'd wind up with:
class func currentDevice() -> UIDevice?
And you'd need to explicitly unwrap that every time you used it (ideally with an if let block). That would very quickly drive you insane, and for nothing. currentDevice() always returns a value. The Optional is an artifact of bridging to ObjC.
So they invented a hack to work around that (and I think it really is a hack; I can't imagine building this feature if ObjC weren't in the mix). That hack says, yes, it's an Optional, but you can pretend it's not, and we promise it's always going to be a value.
And that's !. For this kind of stuff, you basically ignore the ! and pretend that it's handing you back a UIDevice and roll along. If they lied to you and return nil, well, that's going to crash. They shouldn't have lied to you.
This suggests a rule: don't use ! unless you really need to (and you pretty much only need to when bridging to ObjC).
In your specific example, this works in both directions:
func valueForAttribute(key: String!) -> AnyObject!
Technically it takes an Optional<String>, but only because it's bridged to NSString*. You must pass non-nil here. And it technically returns you Optional<AnyObject>, but only because it's bridged to id. It promises that it won't be nil.
According to the Swift-eBook, which states the following
„Trying to use ! to access a non-existent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value.“
I would answer to your first two questions with Yes.
Do I need to include an if let block when examining it...
No, this is not necessary.

Replacement for use of nil in dictionaries in objective-C

I'm working in the IPhone SDK, and am pretty new to objective-c. Right now I'm working with NSUserDefaults to save and restore setting on my IPhone app. In order to save the classes that have been created, I encode them into dictionary form, and then save the NSdictionary.
My problem is that I can't find a reasonable way to store a non-value (I.E. a class variable that is nil) in the dictionary in a reasonable way. To be more specific, lets say I have a class "Dog" and it's got NSString *tail-color. Lets say I'm trying to save a class instance of a dog without a tail, so tail-color for that instance is nil. What is a reasonable way of saving dog as a dictionary? It won't let me save nil into the NSdictionary. #"" isn't good, because if I do if(#""), #"" is true. I would like it to be false like nil.
I hope my question makes sense, and thanks for your help!
If you don't store anything for that key, nil will be returned when you call objectForKey:. If you check for nil when reading the data in, would that be enough? Optionally, you can use objectsForKeys:notFoundMarker: that will return a default value instead of nil.
So, store nothing at all in the dictionary for a value you don't have, and use a strategy for handling that value missing when reading.
You could use NSNull, but that doesn't feel standard, IMO.
You can use NSNull. Instantiate it like this:
[NSNull null]
I would recommend Archiving to save and restore your objects, however.
You should use NSNull to represent nil objects in collections
The best solution is to not save the values which are 'nil' in your case. While reading if the value is not present for your given key the dictionary will return you 'nil'.