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

Simon Di Giovanni
Simon Di Giovanni
8,429 Points

Help please.. Getting frustrated with this code challenge

I really do not understand this at all. How am I supposed to do this?

I copied the answer that someone provided in the questions section for the init? part of the challenge, because it made no sense. We haven't learned about using init? methods before yet we're expected to do this in the challenge?

Anyway. How do I retrieve keys from the dictionary when there is no dictionary. It makes no sense.

If someone can please explain this to me I would much appreciate it.

Regards

Simon

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

}

6 Answers

Tassia Castro
seal-mask
.a{fill-rule:evenodd;}techdegree
Tassia Castro
iOS Development Techdegree Student 9,170 Points

I'm CREATING a key called "key" and assigning it a value called "value"? So in the init method, we are going through and initialising the method to accept 4 keys?

Yes, you're right

Now.... As you said - a dictionary must have both a key, and a value. This is where my confusion started in the first place. The code challenge asks you to obtain the "values" for each key........... But there is no dictionary.. So I'm not sure what values it wants me to retrieve. Do you have any idea what I'm supposed to do there?

In this task you only need to worry about creating the failable initialiser. The guys from treehouse that will create a dictionary and pass this dictionary to your init? to check if you did it right. Thats why in the challenge task it is said: Use the following keys to retrieve values from the dictionary: "title", "author", "price", "pubDate". You have just to imagine that treehouse created a dictionary like this:

var dict = dict[String : String]()
dict["title"] = "iOS"
dict["author"] = "Simon"
dict["price"] = nil
dict["pubDate"] = nil

And they will judge if your init was created correctly or not by the instance of Book they will get back.

So passing this dict I created above to your init, it should create a Book with a title = iOS and author = Simon and no values for price and pubDate.

Simon Di Giovanni
Simon Di Giovanni
8,429 Points

I fully understand now ?

Thank you so much for your help Tassia.

You've spent a lot of your time helping me, and I really appreciate it. ?

Sorry for wasting so much of your time!

Tassia Castro
seal-mask
.a{fill-rule:evenodd;}techdegree
Tassia Castro
iOS Development Techdegree Student 9,170 Points

Hey Simon,

First of all, I just want to tell you that this is not easy to understand at all. So just take a deep breath and keep going.

This is my solution. Not sure if the solution you copied is like mine but in any case I think that might help you.

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

1)We haven't learned about using init? methods before yet we're expected to do this in the challenge? Yeah, at this point we hadn't indeed. They usually do it just to drive us crazy =D. It is hard but in the end it is helpful. As they always say, developers need to learn new things all the time. But trust me I get your point.

2)Anyway. How do I retrieve keys from the dictionary when there is no dictionary. It makes no sense. So, first of all, you HAVE a dictionary because you always HAVE to pass a dictionary when creating an instance of Book, what you may not have is the key 'title' or 'author' or 'price' or 'pubDate'. But in case the dictionary doesn't have the key 'price' or 'pubDate', this will not be a problem when creating a Book because 'price' or 'pubDate' are optional and as they are optional they can have nil assigned to them.

Let's see an example:

Let's suppose there is an app where users need to fill in a form with information about a book. The user has to type the 'title' and 'author' and it is optional to type the price and pubDate. In other to create the book with the users' input I would have to do something like that.

var dict = [String : String]
dict["titel"] = bookLabel.text
dict["author"] = authorLabel.text

var book = Book(dic)

Would that work? No it wouldn't. Why?

When you pass this dict to the init? of the book, it checks if there is a key 'title' and if there is this key then it assigns its value to the title constant. Don't know if you noticed, but when I created the dict I made a typo and created a key TITEL not 'title'. It is a silly example but trust me it may happen.

Another example may be that I was getting this dictionary from a REST API(Don't know if you are familiar with that but if you are not just think about it as a service on the internet that will return you a dictionary with books). This could also fail. The first time you try to create a dictionary with the information from the API, you would write something like that.

var dict = [String : String]
dict["title"] = dictFromAPI["title"]
dict["author"] = dictFromAPI["author"]

var book = Book(dic)

So, ok that would work.

But it may not work in the future.

The guys that created the api, were indeed returning a dictionary that had those keys 'title' and 'author' but for some reason they decided to change and now instead of returning a dict with a key called 'title' they are returning a key called 'titleBook'.

Hope this helps Simon, Good luck!

Simon Di Giovanni
Simon Di Giovanni
8,429 Points

Hi Tassia,

First of all - thanks for writing this out and helping me out here, really appreciate it ?

So if I understand correctly, the init? Method is simply setting up an instance of Book to accept the "value" from a dictionary. It uses the guard statement to ensure that both "title" and "book" are present, otherwise it returns nil.

So to return the keys, I should be creating a function that returns the appropriate key for each value of the dictionary that is input?

Please let me know if I've got the right idea...

Cheers

Simon

Simon Di Giovanni
Simon Di Giovanni
8,429 Points

I also am extremely confused with the initialiser....

You're example shows that you're initialising Book with dict["author"] for example.

But the initialiser accepts [String : String]. I don't understand how this works.

When I try and create an instance of Book with the above initialiser, it asks me to input a dictionary, not 1 String?

How am I supposed to retrieve a key this way?

Tassia Castro
seal-mask
.a{fill-rule:evenodd;}techdegree
Tassia Castro
iOS Development Techdegree Student 9,170 Points

Ohhh, try this way..

var dictFromTheAPI = [String: String]() // I forgot to add the parentheses
dictFromTheAPI["title"] = "iOS"
dictFromTheAPI["author"] = "Simon"
var dict = [String : String]()
dict["title"] = dictFromTheAPI["title"] //Retrieving the value of the key 'title' from the 'dictFromTheAPI' thats equal to 'iOS' and assigning this value to the key 'title' of the 'dict'.
dict["author"] = dictFromTheAPI["author"]

Does it work this way?`

So if I understand correctly, the init? Method is simply setting up an instance of Book to accept the "value" from a dictionary. It uses the guard statement to ensure that both "title" and "book" are present, otherwise it returns nil.

Perfect?

So to return the keys, I should be creating a function that returns the appropriate key for each value of the dictionary that is input?

I don't understand that. Can you give me more details?

Tassia Castro
seal-mask
.a{fill-rule:evenodd;}techdegree
Tassia Castro
iOS Development Techdegree Student 9,170 Points

Ahhh, I think that now I got what you mean..

"But the initialiser accepts [String : String]. I don't understand how this works."

[String: String] in Swift is a Dictionary. So the init is right when it asks you a dictionary. You have to pass a dictionary where the keys are String and the values are String as well.

Like this one here.

var dict = [String : String]()
dict["title"] = "title" 
dict["author"] = "author"

var book = Book(dict: dict)
Simon Di Giovanni
Simon Di Giovanni
8,429 Points

Yes I understand that the init method is asking for a dictionary

But how would I obtain the values in the dictionary, using only the keys? The init method asks for both a value and a key?

Tassia Castro
seal-mask
.a{fill-rule:evenodd;}techdegree
Tassia Castro
iOS Development Techdegree Student 9,170 Points

I think your problem now is understanding how a dictionary works.

"A dictionary stores associations between keys of the same type and values of the same type in a collection with no defined ordering. Each value is associated with a unique key, which acts as an identifier for that value within the dictionary." documentation

That's the way a dictionary works. You have to create one with key:value.

In our example we created one of type String:String var swift dict = [String : String]()

And after you have to populate this dictionary with a key and a value associated to it. dict["title"] is a key of type String and "title" is a value of type String that I'm assigning to the key.

dict["title"] = "title" 

So, later if you need to access its value you just use the key you want and that will return the value that is associated to that key.

The init method asks for a dictionary and a dictionary must have at least one key and one value (so yeah...the init method asks for both a value and a key), otherwise the dictionary is empty.

if you do this:

var dict = [String : String]()
//dict["title"] = dictFromTheAPI["title"]
//dict["author"] = dictFromTheAPI["author"]
var book = Book(dict: dict)// passing an empty dictionary 
book?.title

You will be passing an empty dictionary to the init. So you will have created a dictionary called dict where the key TYPE is a String and the VALUE type is a String. The init will accept this dict but when it tries to create a book, looking for the key "author" or "title" it will not find this key and consequently will not be able to get the value of the key.

Simon Di Giovanni
Simon Di Giovanni
8,429 Points

I think I finally understand now - by typing

dict["key"] = "value"

I'm CREATING a key called "key" and assigning it a value called "value"? So in the init method, we are going through and initialising the method to accept 4 keys?

Now.... As you said - a dictionary must have both a key, and a value. This is where my confusion started in the first place. The code challenge asks you to obtain the "values" for each key........... But there is no dictionary.. So I'm not sure what values it wants me to retrieve. Do you have any idea what I'm supposed to do there?

Simon Di Giovanni
Simon Di Giovanni
8,429 Points

And you create a dictionary, then you somehow assign it only 1 string

dict["author"]

How does this work? Isn't a dictionary like this [String : String]?