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

Amitai Blickstein
Amitai Blickstein
6,863 Points

Playground etc. is implying (in the error msg.) that I need to understand generics to code this properly. Do I?

I don't think I'm getting this, but that's why I'm asking:

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

    init?(withDictionary dict: Dictionary<String, String>) {
        guard self.title = dict["title"] else {return}
        guard self.author = dict["author"] else {return}
        self.price = dict["price"]
        self.pubDate = dict["pubDate"]
    }
}

TY!

2 Answers

Martin Wildfeuer
PLUS
Martin Wildfeuer
Courses Plus Student 11,071 Points

No, I wouldn't say your errors have anything to do with generics. There are two problems with your code. Let me post the working version first:

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

    init?(withDictionary dict: Dictionary<String, String>) { // See comment below!
        guard let title = dict["title"] else { return nil }
        self.title = title

        guard let author = dict["author"] else { return nil }
        self.author = author

        self.price = dict["price"]
        self.pubDate = dict["pubDate"]
    }
}

1. You have to use let to unwrap optionals

Without let, the optional value is not unwrapped and therefore cannot be assigned to a non-optional property. That is, you cannot use guard this way but have to use an intermediate constant like above.

2. Explicitly return nil when your init? should fail

A failable initializer either returns nil or an instance of itself. You have to explicitly return nil if your initializer should fail. Using return alone will return Void instead of nil. This triggers the following error: 'nil' is the only return value permitted in an initializer

Hope that makes sense :)

Amitai Blickstein
Amitai Blickstein
6,863 Points

Thank you.

Regarding No. 2, that's what I did the first n times; removing nil was me shooting in the dark [after shooting with the lights on proved to be ineffective], not knowing what went wrong.

No. 1 is helpful. But...
...can you explain why your code gets me a:

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

anyway?

:) thanks again,
Amitai

PS I noticed that in the Treehouse code editor, { return nil } (with spaces) gets syntax highlighting, while my {return nil} did not. Is that just cosmetic, or a bug?

PPS Do you know why "> Bummer...etc" is not being Markdown'ed into block quote style?

Martin Wildfeuer
Martin Wildfeuer
Courses Plus Student 11,071 Points

Hey there! Sorry, I did not give that a try in the challenge, so I didn't realize it wouldn't pass. Although the code above works, code check seems to be picky about the dictionary type annotation. Moreover, it won't let you pass when you have an external name for the first parameter.

The following will pass:

init?(dict: [String : String]) {
    ...
} 

whereas this won't:

init?(withDictionary dict: Dictionary<String, String>) {
    ...
} 

The external parameter name could be anything, so I do understand why code check will not test for all possible combinations but rather expects a first paramter without external name.

As for the type annotation, this does not really make sense, because Apple says those should be considered equivalent.

From Apple docs:

// The Swift language provides the following syntactic sugar for the Swift
// standard library Dictionary<Key, Value> type: [key type: value type]
// In other words, the following two declarations are equivalent:

let someDictionary: [String: Int] = ["Alex": 31, "Paul": 39]
let someDictionary: Dictionary<String, Int> = ["Alex": 31, "Paul": 39]

I always recommend testing code on playgrounds as well, as a web interface can't really provide reliable feedback and code highlighting in many ways. Sometimes, even the console drops out, although it should display errors.

Cheers!