Having optionals is very helpful in that if you decide to call a function on it, it will not crash and simply return nil.
In our case, we created a class where if its dictionary has valid entries, others can use that class and query it.
However, if that dictionary does not have anything, then execution would continue without a crash.
Quick note about dictionaries
A dictionary is an unordered collection that stores multiple values of the same type.
Each value from the dictionary is associated with a unique key. All the keys have the same type.
The type of a dictionary is determined by the type of the keys and the type of the values. A dictionary of type[String:Int] has keys of type String and values of type Int.
Declare Dictionaries
To declare a dictionary you can use the square brackets syntax([KeyType:ValueType]).
1 |
var dictionary: [String:Int] |
You can access specific elements from a dictionary using the subscript syntax. To do this pass the key of the value you want to retrieve within square brackets immediately after the name of the dictionary.
Because it’s possible not to have a value associated with the provided key (i.e, nil) the subscript will return an optional value of the value type
Thus this means that
1 2 3 4 5 6 7 8 9 |
private var strStrDict = [String:String]() // where strStrDict["ricky"] = "Merry Xmas!" let temp = strStrDict["ricky"] // temp is of type String? (Optional String) print("\(temp)") // Optional("Merry Xmas!") print("\(temp!)") // Merry Xmas! |
Hence, to unwrap the value returned by the subscript you can do one of two things: use optional binding or force the value if you know for sure it exists.
Example 1
If we have a valid property in order to initialize the dictionary, we return a valid self object. This let’s others create and query our OutOfBoundsDictionary.
If our property name does not exist, then we do not want others to be able to query. Thus in the initialization function, it put a ? to denote that what we return is optional self. If the name does not exist, then we return nil. When we return nil, any function calls on a nil, will simply be ignored.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
class OutOfBoundsDictionary { private var countryLocalizedDictionary = [String:String]() public var name : String? // initialize with "Ricky", or leave empty init?() { if let validName = name { countryLocalizedDictionary[validName] = "Sour" } else { return nil } } public func findPerson(firstName: String) -> String? { if let validPerson = countryLocalizedDictionary[firstName] { return validPerson } return nil } } let a = OutOfBoundsDictionary() // property name is set here let lastName = a?.findPerson(firstName: "Ricky") // if a is valid, it will run through the function. // if not, then exection simply skips and continue if let validName = lastName { print("valid name - \(validName)") } |
Thus, if name is initialized, then execution will run through normally and print a valid last name.
If property name was not initialized, then a is returned as nil and calling any functions on it will be ignored.
Another way to do it
…is to have a standard initializer. Return a valid self object. However due to not having any entries in the dictionary, when other objects try to use findPerson with a firstName, it will return nil. And thus, will not print anything
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class OutOfBoundsDictionary { private var countryLocalizedDictionary = [String:String]() public var name : String? init() { if let validName = name { countryLocalizedDictionary[validName] = "Sour" } } public func findPerson(firstName: String) -> String? { if let validPerson = countryLocalizedDictionary[firstName] { return validPerson } return nil } } let a = OutOfBoundsDictionary() // returns valid object let lastName = a.findPerson(firstName: "Ricky") if let validName = lastName { print("valid name - \(validName)") } |