[MUSIC PLAYING]
SPEAKER: Hello, everybody.
Today, I'm going to show you how to connect the SwiftUI
application with Firebase and fetch data
from Cloud Firestore.
So Firestore is a document-based NoSQL database
that allows you to synchronize data in real time.
This is especially useful for applications
that allow users to share data with other users
or with other devices.
And the best thing about it is all
of this comes for free right out of the box
without any implementation effort on your end.
So let's step right in, and I'm going to show you
how to implement this.
So here, I've got a simple application
that I've prepared which displays a list of books,
as we can see in the preview pane over here.
I have defined a static array to hold our books.
And down here in my books list view,
you can see that I'm using a list view to iterate over
the array of books, and then display their details
in a number of text views.
If we take a look at our data model,
we can see that I've got a number of attributes
here such as title, author, and number of pages for my book.
And I have also made it identifiable so
that we can use it in our list view.
I've also gone ahead and connected the project
to Firebase, as you can see by the presence
of the GoogleService.plist file here.
And also, the pod file contains the pods that we need.
If you are new to setting up projects for Firebase,
I encourage you to head over to the documentation, which
goes into great detail and explains how to do that.
And there's even a short video that walks you through it.
While we're here in the browser, let's quickly
look at the Firebase project I created.
And in the project, I also instantiated Cloud Firestore
and prepared a couple of sample documents for us.
So Firestore stores data in documents.
And you can see, I've created two documents here,
which represent two books.
So for example, I've got "The Pragmatic Programmer,"
and another book is "Changer" by Matt Gemmell.
The documents are organized in a collection
which is named "books."
And what we want to do next is subscribe
to this collection in our application
and make sure that we get any updates so that we
can display any updates that are made to the data in our view.
So let me go back to my application.
And probably the easiest way and the cleanest way
to implement this is to build a view model.
So we already have a model.
We have a view.
So the view model basically sits in the middle
and translates between the model and the view.
So let's go ahead and create a new file here.
It's a new Swift file.
And let's call it BooksViewModel.
And then I'm going to create a new class here and name
it BooksViewModel.
And the main responsibility of the class
is to hold the collection of books.
So let's define a variable to hold our books
and instantiate an empty array.
Next, I want to write a function that connects to Firestore
and subscribes to any changes that
happen on our books collection.
So the first thing to do is import Firestore.
And then get a handle to our default Firestore instance.
private var db equals Firestore.firestore.
And then we can go ahead and write
a function fetchdata, which we can
use to subscribe to our data.
So let's first get our collection
and read the documents from our collection.
So let's do that.
So db.collection books addSnapshotListener.
And the snapshot listener has two parameters, querySnapshot
and error.
And the querySnapshot holds the documents from our collection.
So let me implement a guard here to make sure
that we get a collection of documents,
because it might be null.
And if there are no documents, we will just print a method,
and then return.
So at this point, we know we have documents.
And then we can go in and transform those documents
into book models.
And a good way to do that is to use the map operation.
So documents.map.
And then we can do a transform.
And we get the queryDocumentSnapshot.
And here is a book that we want to return.
So now, we want to go into each of the document snapshots
and read the information that is in the document snapshot.
So each document snapshot represents one document.
So queryDocumentSnapshot.
And then we'll get the data property.
And you can see that it is a dictionary which
maps from string to any.
And the string part of this basically
are the attribute names that we define
on our document in Firestore, and the any's are the values.
So let's get this and store it in a variable.
And then read the various parts into local variables as well.
So author equals data.
Author-- let pages equals data pages.
And then we can instantiate a book instance
and use the attributes that we just fetched to initialize it.
And then we can return the book from our closure.
And you will notice that this is a problem here.
So Swift complains that the title here
needs to be a string, but what we give it is an any optional.
And that is because the data contains
a dictionary which maps from string to any, as I showed you
before.
So what we want to do is we want to typecast the any
into the correct data type.
So let's cast them to a string.
And if there is a null value, we will return a default value
like this.
And then for the number of pages,
we're going to cast to int.
And if there is no value, we will return 0.
So this should be fine now.
And let me simplify this--
like that.
And then, of course, we need to assign
the result of our map operation to the books array up here.
self.books equals documents.map.
Nice.
So, almost done.
There are two things that we need
to do before we can use our BooksViewModel in the Swift UI.
And the first thing is we need to make sure
that we implement from ObservableObject
and mark up any attributes that we
want to connect to our UI using the @Published property
wrapper.
So that's that.
Now, we can go back to our book list view
and actually start using our new view model.
So let me create a new local variable here and instantiate
our BooksViewModel like this.
And of course, we need to make sure
that Swift knows that this is an observed
object, so it knows that SwiftUI needs
to manage the state handling.
ObservedObject.
There we go.
OK.
And then we can use this down here in our list view.
And because we've got a property called books on our view model,
this works transparently.
So that's that.
We can now get rid of our static array.
And we finally need to make sure that our fetch data
method is called.
A good way to do that is here in the onAppear callback.
And what we want to do is call self.viewModel.fetchData.
All right.
So let me start the application in the simulator
and bring up both the simulator and Firestore right here.
And you will notice that instead of showing the three
books that we defined in our static array,
it will now only display the two books that it fetches
from our books collection here.
And we can make a change.
So for example, let me change the number of pages
for this book from 521 to 576.
And once I hit Update, you will notice that the UI will
update immediately like this.
And we can also add a new document.
So I've got this book here by Matt Gemmell.
Really recommend it.
So let's add this book.
I will let Firestore manage creating a new ID for me.
And then I'll just need to specify a field for our book.
So the title is "Tall."
The author is Gemmell.
And the number of pages--
let me quickly take a look.
It's 416.
And it's a number.
Once I hit Save, the new book will appear
in the simulator like this.
And I want to show you one final thing.
So what happens if I delete a book?
So let's delete "The Pragmatic Programmer."
We can do that using the overflow menu here.
Delete Document.
And once I confirm, you will see that the book disappears
from our UI.
Great.
So that's basically how you connect to Firestore and fetch
data.
Very straightforward.
There is one thing that we need to take care of that is--
where there's some room for improvement.
So if we take a look at the way how
we map our data from the documents to our book
instances, that seems to be a lot of code,
and also, it doesn't seem to be very safe.
So I'd like to optimize this, but this is something
that we're going to look into the next time.
So thanks for watching, and I will see you next time.
[MUSIC PLAYING]