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 Initializing Optional Values

I am not sure where went wrong.

The task is: In the editor, you have a struct named Book which has few stored properties, two of which are optional.

Your task is to create a failable initializer that accepts a dictionary of type [String : String] as input and initializes all the stored properties. (Hint: A failable init method is one that can return nil and is written as init?).

Use the following keys to retrieve values from the dictionary: "title", "author", "price", "pubDate"

Error: Your code could not be compiled.

optionals.swift
struct Book {
    let title: String
    let author: String
    let price: String?
    let pubDate: String?

    init?(dictionary: [String: String]){
        if let title = dictionary["title"], let author = dictionary["author"] {
          self.title = title
          self.author = author
        } else {
          return nil
        }
        self.price = dictionary["price"]
        self.pubDate = dictionary["pubDate"]
    }
}

6 Answers

Hi Eugene,

That Challenge doesn't want you to use the word "dictionary" as the name for the parameter. Try changing the parameter name to something like "dict" and you should be able to pass it. Also β€”even though your current code will pass β€” consider using a guard statement as it really is the best option for this situation.

Pasan Premaratne
Pasan Premaratne
Treehouse Teacher

Hey Eugene,

The directions should have said use dict as your initializer argument name. Sorry for the confusion, I've modified the directions!

Jeff Ripke
Jeff Ripke
41,989 Points

Having a hard time figuring out how to use the guard statement in this failable init:

What am I doing wrong?

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

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

    }
}
Matthew Connolly
seal-mask
.a{fill-rule:evenodd;}techdegree
Matthew Connolly
iOS Development Techdegree Student 11,595 Points

Remember that you have to initialize all the properties in your struct. Right now you are initializing only price and pubDate.

Also, for you guard statement, think about what properties of Book are absolutely necessary to create an instance of Book, those are the properties you want to "guard" against.

Do you need a price and a pubDate to create an instance?

Hey Jeff,

title and author β€” as opposed to price and pubDate β€” cannot be nil; they have to be Strings. The place where you would set these properties is inside that fail-able initializer. Basically, you want to return nil out of that initializer if either title or author turn out to be nil. Otherwise, you want to set title and author to their corresponding values from the dictionary. You should also set price and pubDate here but note that β€” because they're optional Strings β€” you can just set them directly (i.e., without an if-let or a guard-let etc.).

Jeff Ripke
Jeff Ripke
41,989 Points

Thanks for helping. I am still confused on how to do this. I created the guard statement for title and author but still getting errors.

    init?(dict: [String: String], price: String, pubDate: String) {
        guard let title = dict["title"], let author = dict["author"] else {
            return nil
        }
        self.price = price
        self.pubDate = pubDate
    }
Matthew Connolly
seal-mask
.a{fill-rule:evenodd;}techdegree
Matthew Connolly
iOS Development Techdegree Student 11,595 Points

Hey Jeff

Your guard statement looks much better, great job! That's exactly how you want to implement it.

Now you have to finish initializing. Think about how the init? is going to work. If you pass the guard statement (e.g. your title and author are not nil) you will move onto initializing the Book instance. Currently, you are only initializing with self.price and self.pubDate.

I would also adjust your parameters to only include a dictionary like below and reference the price and pubDate within the function:

init? (dict: [String : String]) {
    /* guard statement */

    self.title = /*insert code*/
    self. author = /*insert code*/
    self.price = dict["price"]
    self.pubDate = dict["pubDate"]
}
Jeff Ripke
Jeff Ripke
41,989 Points

Thanks that makes since now, I was think the guard statement was the init.

Sayuri Katz
Sayuri Katz
6,148 Points

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

init?(dict: [String: String], price: String, pubDate: 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"]
}

}

Make sure you are creating a failable initializer that accepts a dictionary as an argument for initialization

Alen Kirm
Alen Kirm
7,632 Points

Well, that was very challenging. Thank you Matthew and Jeff for help.

The solution for this challenge is:

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"]
    }