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 Swift 2.0 Enumerations and Optionals Introduction to Optionals Recap on Optionals

Berry Loeffen
Berry Loeffen
4,303 Points

Adding a function to the next challenge.

Adding the function bookDetails to the struct. Is this the way to do it or is there a shorter version possible? I don't think a Guard statement can be used here, so I used "else if let" statements. Any ideas? or is there just no shorter way to do this?

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

    init?(dict: [String: String]) {
        guard let title = dict["title"], let author = dict["author"] else {return nil}
        self.title = title
        self.author = author
        self.price = dict["price"]
        self.pubDate = dict["pubDate"]
    }
    func bookDetails() -> String {

        if let price = price, let pubDate = pubDate {
            return "\(title), \(author), \(price), \(pubDate)"
        }

        else if let price = price {
            return "\(title), \(author), \(price)"
        }
        else if let pubDate = pubDate {
            return "\(title), \(author), \(pubDate)"
        } else {
            return "\(title), \(author)"}
    }    
 }
Greg Kaleka
Greg Kaleka
39,021 Points

Just came across this. Gianpiero's answer is very elegant. Just to point this out, though - you definitely could use guard. It's a bit sticky, though. I'll show it to you "clean" and then walk through the logic. It's not the most elegant thing... but it works!

cleanVersion.swift
func bookDetails() -> String {

    guard let price = price else {
        guard let pubDate = pubDate else {
            return "\(title) by \(author)"
        }
        return "\(title) by \(author), published \(pubDate)"
    }

    guard let pubDate = pubDate else {
        return "\(title) by \(author) for \(price)"
    }

    return "\(title) by \(author), published \(pubDate). On sale for \(price)"

}
annotatedVersion.swift
// There are 4 possibilities
// 1. price=nil && pub=nil
// 2. price=nil && pub!=nil
// 3. price!=nil && pub=nil
// 4. price!=nil && pub!=nil

func bookDetails() -> String {
    guard let price = price else {
        // 1. or 2.
        guard let pubDate = pubDate else {
            // 1. price=nil && pub=nil
            return "\(title) by \(author)"
        }
        // 2. price=nil && pub!=nil
        return "\(title) by \(author), published on \(pubDate)"
    }
    // 3. or 4.
    guard let pubDate = pubDate else {
        // 3. price!=nil && pub=nil
        return "\(title) by \(author) for \(price)"
    }
    // 4. price!=nil && pub!=nil
    return "\(title) by \(author), published on \(pubDate) for \(price)"
}

1 Answer

You should start concatenating the non optional string and then add the optional.. like:

func bookDetails() -> String {
   var details = "\(title), \(author)"
   if let price = price {
      details += ", \(price)"
   }     
   if let pubDate = pubDate {
      details += ", \(pubDate)"
   }
   return details
}

Shortened with ternary operator:

func bookDetails() -> String {
   return "\(title), \(author)" + (price != nil ? ", \(price)" : "") + (pubDate != nil ? ", \(pubDate)" : "")
}

But if you want a glimpse about how fun is the language, you can use closures and array methods to do the work for you:

func bookDetails() -> String {
   return [title, author, price, pubDate].flatMap{$0}.joinWithSeparator(", ")
} 

flatMap is a filtering function that returns an Array without the nil values (the parameter $0 in curly braces is a shortened syntax of a closure, if you didn't study it yet you will be surprised), and JoinWithSeparator in pretty obvious.

Have fun programming! :)