Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS Enumerations and Optionals in Swift Introduction to Optionals Early Exits Using Guard

Why do we "guard" a name and an age here instead of address?

In additional link (http://swift.ayaka.me/posts/2015/10/5/optional), we have a struct with 2 variables and 1 optional variable (just like here in Friend). However, while here we "guard" non-optional variables, in the example on that blog we "guard" an optional variable. And so far the second approach seems more reasonable to me. So, what's the right way to do it?

Charles Kenney
Charles Kenney
15,604 Points

in the example on that blog we "guard" an optional variable. And so far the second approach seems more reasonable to me. So, what's the right way to do it?

Am I missing something here? It seems incredibly dubious to guard an optional; that would make it a non-optional. Could you quote exactly what you are talking about in the article?

You can find it right under guard section:

var displayName: String {
    guard let middleName = middleName else {
        return givenName + " " + familyName
    }
    return givenName + " " + middleName + " " + familyName
}
Antonis Tsagaris
Antonis Tsagaris
17,511 Points

After checking the article in the link you provided, I found the answer:

Anyway, yikes. I don’t know about you, but this looks pretty complicated for something that does a relatively simple task. What’s going on here? First, we’re seeing if dictionary["given_name"] is a String (non-nil since it’s not String?) and assigning it to givenName and doing the same for dictionary["family_name"] for familyName. If both of these are non-nil we assign to their respective properties. Otherwise, we return nil and fail the initializer.

===> Finally, we set middleName outside of the if let because we’re fine if middleName is nil since it’s of type String?. <==

3 Answers

Alright, boys and girls, I finally got it. It took me a while to connect all dots together but I finally did it and because there may be other who may be confused about this as well, I decided to explain it to you all. In case my explanation isn't clear enough, just watch this and previous video over and over again because in those 2 videos the answer is hidden.

And now to the explanation. My confusion was with properties of Friend struct. We have two non-optional properties (name, surname) and an optional property address. What I didn't understand at first was why did we "guard" two properties which couldn't be nil? You guard only those which are optional, right?

What I completely missed was that we weren't working with properties, but with dictionaries. And there's a chance such pair doesn't exist. That's why dictionaries return key's value as an optional. So that's why we used guard - to make sure key's value isn't nil but that it is an actual value.

But what about address? We are still working with dictionaries and an address can therefore be nil, right? You are completely right. But look at struct Friend again. While name and surname HAVE TO be strings, address CAN BE either string or nil. If you have your friend's address, it's great and you can save it as string. But if you don't know his address, no problem. I mean, you may have met him recently and so it's still quite soon to know it or he's from a different country and in such cases we barely know their addresses. And for such cases, we accept that address can be nil

Hopefully this will help you and if you have any question, don't hesitate and ask me! :)

Cam Crain
Cam Crain
4,328 Points

Great explanation Jiri! It helped a lot.

Charles Kenney
Charles Kenney
15,604 Points

Ah, now that I have more of a context I can answer your question. It is a matter of opinion, however there are more elegant ways. My personal take on this would be to assign a default value as a fallback ("??"). Then I could have the whole block on one line.

struct Person {
    let givenName: String
    let familyName: String
    let middleName: String?
    var displayName: String {
        // My solution
        return "\(self.givenName) \(self.middleName ?? "") \(self.familyName)"
    }
}

That single-line block would replace that bloggers four-line block.

To clarify though, I think what you are suggesting is more readable than the 'if let/else' method that apple teaches in the 3.1 Docs. I just didn't understand what you were getting at, at first, lol.

Hope this helps,

Charles

Alright, I guess I'm just pretty bad at explaining :D

In the Treehouse video, on guard line we work with variables which are NON-OPTIONAL In the blog article, on guard line we work with a variable which is an OPTIONAL

See the difference? I just don't understand why once we work with non-optional and then with optional

At least here (section Early Exit) https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html, they work with optional values

Antonis Tsagaris
Antonis Tsagaris
17,511 Points

This is where I am confused as well. I thought that I understood Guard, until I tried to solve the problem. My solution is the following:

struct Book {
    let title: String
    let author: String
    let price: String?
    let pubDate: String?

    init?(dict: [String: String]){
      guard let priceNew = dict["price"], let pubDateNew = dict["pubDate"] else {
        return nil
      }

      self.title = dict["title"]
      self.author = dict["author"] 
      self.price = priceNew
      self.pubDate = pubDateNew
    }   
}

If you run this solution in xCode you get the following error:

error: value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'? self.author = dict["author"]

My question is: Why not guard the optional values?

A possible explanation is the one I thought last night while showering: Maybe, if we say that price and pubDate are optional, then we might NOT pass a value (nil). But title and author are not optional so we must check for the absence of value, this is why we use guard on these 2 (title, author) instead on price and pubDate.

Was my showering epiphany correct?

Another question:

During

if let variable1 = someOptional 

OR

guard let variable1 = someOptional

isn't the variable1 the unwrapped value of someOptional? If this is the case, what happens if we replace the someOptional with a nonOptional value?

PS: on Pasan's video "Early Exits using Guard" on 0:42 he says: "The expression has to be one that returns an optional value". So how can a non-optional constant return an optional value? Or is it that only non-optional constants that return optional values? Confused! :|

Thanks!

Hi mate, I have just added an answer which should explain it to you. Hopefully it will help you. Cheers! :)