Do i have to state a "return nil" statement when my return value in a function is an optional? - swift

So for example i have the following code:
var meals: [String: Meal] = ["Breakfast": Meal(food: ["Bagel", "Orange Juice", "Egg Whites"], calories: 530)]
func logging (mealTime: String) -> Meal? {
if let a = meals[mealTime] {
return a
} else {
return nil
}
}
Do i need to state a "return nil" if my return value is already an optional? Because the solution to this exercise was just this:
func logging(mealTime: String) -> Meal? {
return meals[mealTime]
}
And if I do not have to add the return nil, why is that?
Thanks in advance!

Just to clarify:
Parameter:
mealTime: String
This string could be a key in your dictionary.
Function (how it works): this function wants to check if this key exists and if it is so, it returns the value (that is a Meal object).
What did you do?
if let a = meals[mealTime] {
return a
} else {
return nil
}
You are checking (if let) if there is a value with that string key and you are assigning that value to your constant (a). Eventually you return that value. If no value has that key in your array then you return nil.
What is the right answer about?
Because this function returns an Optional Meal, you can skip checking if it exists, that's why the right answer is just:
func logging(mealTime: String) -> Meal? {
return meals[mealTime]
}
This function returns nil if there is not value with that key and returns the value if it has that key.

Related

How to get the First Character in a name

I have below func in my class.
static func getFirstCharInName(strName: String) -> String {
let firstCharInName = String(strName.first)
return firstCharInName.trim()
}
I encountered this err:
Value of optional type 'Character?' must be unwrapped to a value of type 'Character'
What seems to be the problem?
Thanks
func getFirstCharInName(strName: String) -> String {
let indexStartOfText = strName.index(strName.startIndex, offsetBy: 0)
let indexEndOfText = strName.index(strName.startIndex, offsetBy: 0)
let firstChar = String(strName[indexStartOfText...indexEndOfText])
return firstChar
}
This error means that the expression has optional value (the value can be nil) that is not yet unwrapped, strName.first returns an optional value of Character?, but your function demands a returning type of String which is not an optional type.
So, in order to fix this, you need to unwrap the optional value strName.first, it seems like you are not familiar with optionals, here's the code for your case (choose one from two options):
func getFirstCharInName(strName: String) -> String {
// option 1: force unwrap - can cause fatal error
return String(strName.first!)
// option 2: optional binding
if let firstCharInName = strName.first {
return String(firstCharInName)
} else {
// if the optional value is nil, return an empty string
return ""
}
}
PS. I don't really understand the function trim() in your question, but if you mean to strip away the blank spaces like " ", you can do:
firstCharInName.trimmingCharacters(in: .whitespaces)
Avoid the optional simply with prefix, it's totally safe. if there is no first character you'll get an empty string.
static func getFirstChar(in name: String) -> String { // the function name getFirstChar(in name is swiftier
return String(name.prefix(1))
}
I don't know what the trim function is supposed to do.
It means that value of optional type 'Character?' (as result of your part of code strName.first) must be unwrapped to a value of type 'Character' before you will be gonna cast it to String type.
You may use this variant:
func getFirstCharInName(strName: String) -> String {
return strName.count != 0 ? String(strName.first!) : ""
}
As you can see, the exclamation point is in the string strName.first! retrieves the optional variable as it was needed.
you can do something like that:
extension String {
var firstLetter: String {
guard !self.isEmpty else { return "" }
return String(self[self.startIndex...self.startIndex])
}
}
then
let name = "MilkBottle"
let first = name.firstLetter // "M"

swift generics return first and last element

I'm trying to get used to generics (never used them in objc) and want to write a toy function that takes an object of any type () and returns the first and last element. Hypothetically, I'd only use this on an array or a string - I keep getting an error that has no subscript members. I totally understand that the error message is telling me swift has no clue that T may potentially hold a type that does have subscripts - I just want to know how to get around this.
func firstAndLastFromCollection<T>(a:T?) {
var count: Int = 0
for item in a as! [AnyObject] {
count++
}
if count>1 {
var first = a?[0]
var last = a?[count-1]
return (first, last)
}
return something else here
}
Do I need to typecast somewhere here (which would kind of defeat the purpose here, as I'd need to downcast as either a string or an array, adding code and lessening how generic this func is)?
If you want to return the first and the last element then it's probably safe assuming the input param is an array of some kind of type.
So you can implement your function this way
func firstAndLast<T>(list:[T]) -> (first:T, last:T)? {
guard let first = list.first, last = list.last else { return nil }
return (first, last)
}
The function does return a tuple of 2 element, both have the same type of the generic element of the input array.
The returned tuple is an option because if the array is empty then nil is returned.
Examples
let nums = firstAndLast([1,2,3,4])
let words = firstAndLast(["One", "Two", "Three"])
As you can verify the type of the generic element into the array becomes the type of the elements inside the tuple.
In the example above nums is inferred to be (Int, Int)? and words (Words, Words)?
More examples
let emptyList: [String] = []
firstAndLast(emptyList) // nil
Extension
Finally you can also write this code as an extension of Array.
extension Array {
var firstAndLast: (first:Element, last:Element)? {
guard let first = self.first, last = self.last else { return nil }
return (first, last)
}
}
Now you can write
let aCoupleOfShows = ["Breaking Bad", "Better Call Saul", "Mr Robot"].firstAndLast
Again, if you check the type of the constant aCoupleOfShows you'll see that is a (first: String, last: String)?. Swift automatically did infer the correct type.
Last example
In the comments you said you wanted the first and last chars of a String. here it is the code if you use the extension above
if let chars = Array("Hello world".characters).firstAndLast {
print("First char is \(chars.first), last char is \(chars.last) ")
}
//>> First char is H, last char is d
If we are talking about collections, let's use the CollectionType:
func firstAndLastFromCollection<T: CollectionType>(a: T) -> (T.Generator.Element, T.Generator.Element)? {
guard !a.isEmpty else {
return nil
}
return (a.first!, a.lazy.reverse().first!)
}
print(firstAndLastFromCollection(["a", "b", "c"])) // ("a", "c")
print(firstAndLastFromCollection("abc".characters)) // ("a", "c")
print(firstAndLastFromCollection(0..<200)) // (0, 199)
print(firstAndLastFromCollection([] as [String])) // nil
If you specify your generic type to also conform to bidirectional index:
func firstAndLastFromCollection<T: CollectionType where T.Index : BidirectionalIndexType>(...) -> ...
then you can call last directly:
return (a.first!, a.last!)
If we decide to implement it using a category, we don't need generics at all:
extension CollectionType {
func firstAndLast() -> (Generator.Element, Generator.Element)? {
guard !self.isEmpty else {
return nil
}
return (self.first!, self.lazy.reverse().first!)
}
}
extension CollectionType where Index: BidirectionalIndexType {
func firstAndLast() -> (Generator.Element, Generator.Element)? {
guard !self.isEmpty else {
return nil
}
return (self.first!, self.last!)
}
}
print("abc".characters.firstAndLast())
Swift is a protocol oriented language. Usually you will find yourself extend protocols more than extending classes or structs.

Check if key exists in dictionary of type [Type:Type?]

How can I check if a key exists in a dictionary? My dictionary is of type [Type:Type?].
I can't simply check dictionary[key] == nil, as that could result from the value being nil.
Any ideas?
Actually your test dictionary[key] == nil can be used to check
if a key exists in a dictionary. It will not yield true if the value
is set to nil:
let dict : [String : Int?] = ["a" : 1, "b" : nil]
dict["a"] == nil // false, dict["a"] is .some(.some(1))
dict["b"] == nil // false !!, dict["b"] is .some(.none)
dict["c"] == nil // true, dict["c"] is .none
To distinguish between "key is not present in dict" and "value for key is nil" you
can do a nested optional assignment:
if let val = dict["key"] {
if let x = val {
print(x)
} else {
print("value is nil")
}
} else {
print("key is not present in dict")
}
I believe the Dictionary type's indexForKey(key: Key) is what you're looking for. It returns the index for a given key, but more importantly for your proposes, it returns nil if it can't find the specified key in the dictionary.
if dictionary.indexForKey("someKey") != nil {
// the key exists in the dictionary
}
Swift 3 syntax....
if dictionary.index(forKey: "someKey") == nil {
print("the key 'someKey' is NOT in the dictionary")
}
You can always do:
let arrayOfKeys = dictionary.allKeys
if arrayOfKeys.containsObject(yourKey) {
}
else {
}
However I really dislike the idea of creating an NSDictionary which can contain optionals.
Try this:
let value = dict[key] != nil
Hope it work for you. Thanks
As suggested here and above, the best solution is to use Dictionary.index(forKey:) which returns Dictionary<Key, Value>.Index?. Regardless of whether your value is an optional type, this returns an optional index, which if nil, definitively tells you whether the key exists in the dictionary or not. This is much more efficient than using Dictionary.contains(where:) which is documented to have "complexity O(n), where n is the length of the sequence."
So, a much better way to write .containsKey() would be:
extension Dictionary {
func contains(key: Key) -> Bool {
self.index(forKey: key) != nil
}
}
I've been advised that dict.keys.contains() is actually O(1), so feel free to use it if you prefer.
I handled it this way in Swift 4:
extension Dictionary {
func contains(key: Key) -> Bool {
let value = self.contains { (k,_) -> Bool in key == k }
return value
}
}
This uses Dictionary.contains(where: (key: Hashable, value: Value) throws -> Bool). By encapsulating it as an extension I have a good shot at updating the implementation to something better without modifying my code. I'm avoiding creating data, which index(forKey:Key) does. I'm hoping it's more efficient than accessing keys since that must create the whole array before searching it.

Determining if Swift dictionary contains key and obtaining any of its values

I am currently using the following (clumsy) pieces of code for determining if a (non-empty) Swift dictionary contains a given key and for obtaining one (any) value from the same dictionary.
How can one put this more elegantly in Swift?
// excerpt from method that determines if dict contains key
if let _ = dict[key] {
return true
}
else {
return false
}
// excerpt from method that obtains first value from dict
for (_, value) in dict {
return value
}
You don't need any special code to do this, because it is what a dictionary already does. When you fetch dict[key] you know whether the dictionary contains the key, because the Optional that you get back is not nil (and it contains the value).
So, if you just want to answer the question whether the dictionary contains the key, ask:
let keyExists = dict[key] != nil
If you want the value and you know the dictionary contains the key, say:
let val = dict[key]!
But if, as usually happens, you don't know it contains the key - you want to fetch it and use it, but only if it exists - then use something like if let:
if let val = dict[key] {
// now val is not nil and the Optional has been unwrapped, so use it
}
Why not simply check for dict.keys.contains(key)?
Checking for dict[key] != nil will not work in cases where the value is nil.
As with a dictionary [String: String?] for example.
The accepted answer let keyExists = dict[key] != nil will not work if the Dictionary contains the key but has a value of nil.
If you want to be sure the Dictionary does not contain the key at all use this (tested in Swift 4).
if dict.keys.contains(key) {
// contains key
} else {
// does not contain key
}
Looks like you got what you need from #matt, but if you want a quick way to get a value for a key, or just the first value if that key doesn’t exist:
extension Dictionary {
func keyedOrFirstValue(key: Key) -> Value? {
// if key not found, replace the nil with
// the first element of the values collection
return self[key] ?? first(self.values)
// note, this is still an optional (because the
// dictionary could be empty)
}
}
let d = ["one":"red", "two":"blue"]
d.keyedOrFirstValue("one") // {Some "red"}
d.keyedOrFirstValue("two") // {Some "blue"}
d.keyedOrFirstValue("three") // {Some "red”}
Note, no guarantees what you'll actually get as the first value, it just happens in this case to return “red”.
My solution for a cache implementation that stores optional NSAttributedString:
public static var attributedMessageTextCache = [String: NSAttributedString?]()
if attributedMessageTextCache.index(forKey: "key") != nil
{
if let attributedMessageText = TextChatCache.attributedMessageTextCache["key"]
{
return attributedMessageText
}
return nil
}
TextChatCache.attributedMessageTextCache["key"] = .some(.none)
return nil
If you want to return the value of the key you can use this extension
extension Dictionary {
func containsKey(_ key: Key) -> Value? {
if let index = index(forKey: key){
return self.values[index]
}
return nil
}
}
if dictionayTemp["quantity"] != nil
{
//write your code
}
If you are dealing with dictionary that may contain nil value for a key then you can check existence of key by:
dictionay.index(forKey: item.key) != nil
For getting first value in dictionary:
dictionay.first?.value // optional since dictionary might be empty

Grabbing values from a dictionary in a more elegant way

I've been playing with swift and am getting quite tortured! Consider:
var myDict : Dictionary <String, String>
//DO SOME MAGIC TO POPULATE myDict with values
<magic being done>
//Now myDict has values. Let's parse out the values of myDict
//This doesn't work
let title : String = myDict["title"]
//This does
let title : String? myDict["title"]
This is because it isn't known whether the key is in the dictionary. What I want to say, though, is "If the title key is in the dictionary, give me that value, else, just give me an empty string"
I could probably write:
var myTitle : String
if let title : String = myDict["title"] {
myTitle = title
} else {
myTitle = ""
}
I believe that works...BUT...it's quite a lot of code for EACH key of the dictionary. Does anyone have any ideas in the swift world on how this is supposed to be written?
RD
You could write an extension on optional:
extension Optional {
/// Unwrap the value returning 'defaultValue' if the value is currently nil
func or(defaultValue: T) -> T {
switch(self) {
case .None:
return defaultValue
case .Some(let value):
return value
}
}
}
Then you can do:
myDict["title"].or("")
This would also work for all optionals.
Note: I started a module to add common helpers like this or on Optional to swift.
You unwrap the value either explicitly:
let title : String = myDict["title"]!
or implicitly:
let title : String! = myDict["title"]
Note that you still have to check whether title is nil or not unless you are really sure it's there.
Edit:
Here's a sample global operator overload for any optional for type T:
#infix func | <T: Any>(lhs: T?, rhs: T!) -> T! {
if lhs {
return lhs!
}
return rhs
}
var myDict : Dictionary <String, String> = ["a": "b"]
let title1 = (myDict["a"] | "") // "b"
let title2 = (myDict["title"] | "") // ""