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

Dalton Keen
Dalton Keen
8,082 Points

Failable Initializers

Objective: "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 as input an initializes all the stored properties. (Hint: A failable init method is one that can return nil and is written as init?). Name the initializer parameter dict.

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

The previous videos explained how to use guard statements in functions so I applied the same logic to the initializer and it doesn't work. I've tried declaring variables using self (ex: let self.title) and no difference. I'm just not sure at all how to go about solving this one. Any help is appreciated.

Thanks

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


    init?(dict: [String : [String : [String : [String]]]])
    {
        guard let title = dict["title"], let author = dict["author"] else {
        return nil
    }

        let price = dict["price"]
        let pubDate = dict["pubDate"]

    }

}

2 Answers

Almost! The type of the dict needs to be [String:String]. Once you've vetted the title and author you get from the dictionary you still need to set the member variables title and author.

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"]
    }
}
Dalton Keen
Dalton Keen
8,082 Points

Ahhh. Got it! Thanks

Could you demonstrate how do declare a new instance of that struct with using the init? I can't seem to figure it out? also why would you use it that way instead of like this.

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

}
func createBook(dict: [String: String]) -> Book? {
    guard let title = dict["title"], author = dict["author"] else {
        return nil
    }

    let price = dict["price"]
    let pubDate = dict["pubDate"]

    return Book(title: title, author: author, price: price, pubDate: pubDate)
}

Christian, re your code: First, the challenge asked you to create a failable initializer, not a function. Second, initializers must be inside their structs, not outside them. And initializers don't return anything. They create objects and initialize their member variables.

Re your request:

let dict1 = [ "title" : "Pride & Prejudice", "author" : "Jane Austen", "price" : "23.95"]
let b1 = Book(dict: dict1)
b1?.title  //"Pride & Prejudice"
b1?.author  //"Jane Austen"
b1?.price  //"23.95"
b1?.pubDate  //nil

Note that the above code must be outside the struct, as it is using the struct to create a Book object (b1) from a dictionary.

If you put the struct and the above code in an Xcode playground (7.3.1.), and then alt-click on b1, you will see, in the popup, that b1 is Book?, i.e., an optional. If you try to remove the ? you will get an error message saying "Value of optional type 'Book?' not unwrapped; did you mean to use '!' or '?'?"

My code works fine the playground. I know the challenge was asking to use init which i did. It just seems easier to me to use a func rather then init, and I was wondering if there is a benefit in using the init method rather then the func like I did.

//this is an instance of my code up above in my last comment.

let newBook = Book(title: "legend of Drittz", author: "r.a. salvator", price: "15.00", pubDate: nil)
newBook.title                  //returns "legend of Drittz"
newBook.author             //returns "r.a. salvator"
newBook.price               //returns "15.00"
newBook.pubDate        // returns nil

//this does not return an error and works perfectly.