>> [music] Stanford University
[ Silence ]
>> Welcome to number
13 of Stanford CS1-93B,
the fall of 2013-14, and
today, I'm going to go
over the requirements
for your final project,
and then I'm going to talk a
little more, a few more slides
about Core Data, and how it
hooks up with UI TableView,
because those two are
a match made in heaven,
and then I'm going to do
this gigantic Core Data
with TableViews demo.
Alright, so you're
final projects.
There's kind of two phases
to your final project;
one is you have to
submit a proposal
for us, which we'll review.
We're mostly just
reviewing it for scope,
to make sure you haven't
picked too big a project
or too small a project.
Okay, we're not, you
know, looking in detail
of every single thing
you're going to do.
We're just trying to
make sure you're headed
in the right direction.
Because over the course of the
final project, you're going
to of course talk to us, and
ask us questions and interact
with us to kind of get an
idea of getting, you know,
hitting a good target
at the end.
So, that is really,
do immediate.
We'd like you to get
us your proposal.
If you know what
you're going to do,
please submit a proposal
as soon as possible.
If you know what
you're going to do,
please submit a proposal
as soon as possible.
If you don't get on it right
away, and submit it as soon
as possible, really though
by next Wednesday would
be the latest we'd want
to hear from you.
And, I hate to say that,
because I know a lot of you wait
until the day before deadline
to do anything, and I understand
that impulse, but this is
something where you want to get
that proposal in sooner,
in case we have issues,
and we can get back to
you, and you either write,
maybe come up with a whole new
proposal if what you're thinking
about is just not going to work.
Then the second phase is
the final project itself,
and that project, the
code for the project,
along with the keynote,
set of keynote slides
for a two minute presentation
about your project are due
on Friday, December 6, okay?
So, that seems like
that's far away, I know,
that's over a month away, right.
It's November 6 right now, but
you got Thanksgiving in there,
so it's really not that far
away, and so your final project,
like a final project
in your class,
where you get multiple weeks to
do it, you do not want to wait
to the last week to get started.
So, get started immediately.
You have everything you need now
to start building
an application.
Yeah, no late days on
the final project at all.
Simply will not accept it late.
Whatever you have on December
6 at midnight, submit it.
I don't care what it is;
submit it, because that's all.
I'm not going to
accept anything.
I just can't, because
I've got a lot of students
who are taking this for a grade
especially, and that's a lot
of time I have to be fair
to those people, and also,
I have to get started
grading immediately.
The presentation that you're
going to do, two minutes,
it's really just going to be
pitching your project to us,
to your fellow classmates.
If you can imagine, it's like
you're trying to pitch a VC
to invest in your
company or to do the app,
or you're just trying to get
people to buy it, or whatever.
It's that kind of presentation.
I'll leave it up to you.
You can certainly do a
live demo if you want.
You'll need iPhone 4S or
later, or you'll need an iPad 2
or later, in order to hook
up to this wonder projection
system we have using Apple
TV mirroring.
But, you don't have
to do a live demo.
Live demos are perilous, as you
can see, what I do each lecture,
but they also kind of can be
effective, and a really good way
to show off your app, so
it's kind of up to you.
And, that presentation
is required.
I will have an alternate
presentation,
which is the last
lecture of the quarter,
which is the week before
the final exam period.
So, that's that.
Yeah, the scope is
basically three weeks
of homework worth of work.
You should know by now
approximately what that is.
Remember in the past
when the people have
to pass both the
homework section
and the final project
separately.
You can't bomb one, and get an A
on the other, and
pass this class.
Your final project has
to work on hardware.
You have to show it
working, either in a demo
in your two minutes, or if
you don't show a live demo
in your two minutes, you
have to show your TA.
Only iOS-SD code counts, so
if your app has a backend,
some server somewhere,
you get no credit
for any of that really.
You're only getting
credit for iOS code, okay.
So, simulate your
backend if you have to,
or if you have the backend from
somewhere else, that's fine,
but don't waste time
doing non-iOS code
in this three weeks,
because you're not going
to get any credit for that work.
And, you'll be graded on
your proper use of the SDK,
and also proper object-oriented
programming,
and your aesthetics will matter.
So, don't put a big
junky-looking UI that just like,
really looks terrible, and yeah,
don't get sidetracked
on non-iOS code.
That's kind of a repeat of
all that slide there, so.
The presentation quality
matters a tiny bit.
It does matter.
Giving your presentation,
effective presentation is a
very important skill to have.
All of you at Stanford should be
good at that by the time you get
out of here, so here's
just another chance
to really practice doing
a good presentation.
Time it; see how long
it's going to take.
You know, run through it
a couple times practicing.
You proposal needs to
have sections in it.
Okay, the first section is
kind of an overall description.
What am I doing?
This is best shown by example,
so I have this example here,
which is a Shakespeare
Director App,
so let's say you're a
director at a theater company,
and you're going to be direction
some Shakespeare plays,
and this is an app
to help you do that.
And so, it has a way to
bring up a Shakespeare play
from the folio database,
and then you can lay
out the blocking, which is
like where the scene is set up,
where the people are
standing and all that stuff
of each scene, lined
up with the dialogue.
And then, it's also got
a dialogue learning mode
for people who want to learn
the dialogue, learn their lines.
It will say the other parts, and
then you can say your own part.
So, you can see that this
is kind of a description
of what it does, as opposed
to how you're going to do it.
Section 2 is what parts
of iOS are you going
to use to implement it.
Okay, it's going to have
TableView with custom cells.
It's going to use the camera.
It's going; you know text
fields with in popovers.
It's going to use AV foundation.
It's going to NS Timer.
It's going to have Core Data,
and where there are
going to be my entities.
It's going to print out the
blocking things to printer,
which is something we
don't cover in class.
And, you're required to
have one feature, at least,
that it was not covered
in lecture.
Okay, and so that task is on
there; not only so you have
to learn something
from a documentation,
instead of my kind of
getting you started with it,
but also so that you
peruse all of iOS
and find out what's in there.
So, don't come to me and say,
oh, can you tell me a feature
to do for non-iOS not
covered in lecture?
It's like, that's part of
the task for you to go figure
out what's out there
and pick something.
Okay. So, that's what
your proposal needs
to have, these two sections.
What it is you're opting to do,
and then what iOS apage you're
going to use that you know
of right now to implement.
Okay? And, here's some
notes, again, you're going
to review these slides offline
to really get a good feel
for what makes a good proposal,
and you can ask on Piazza
for clarifications, etc. Okay,
so, the next topic I want
to talk about is
Core Data still,
but its Core Data and TableView.
How Core Data and
TableView go together.
Because Core Data is a
bunch of, you know, objects,
a big object graph, and
TableViews are really good
for traversing through
object graphs, okay?
So, how do we do this?
There's a great class
in iOS called NSFetched
Results Controller.
This class' only purpose in life
is to link an NSFetchRequest,
which hopefully you'll remember
from two days' ago lecture
with a UI TableView.
That's what it does,
it basically bonds those
two things together,
so that the Fetch; anything
that Fetch would be fetching is
always showing in the TableView,
even if the database is changing
underneath that FetchRequest.
Okay, it's still going to
be updating the TableView.
So, the way this works,
it's really two parts
for the Fetched Results
Controller.
One is it answers
all the questions
in the UI-TableView
data source protocol,
like how many sections,
how many rows and sections,
and even some ones that
you don't know about,
some more advanced ones.
It answers those
questions as well.
So, it's able to answer
all those questions,
using code kind of like that.
Also, it can tell you
at any given time,
what thing in your database,
what entity in your
database is being shown
in a given row, okay?
There's a one to one mapping
between a row in the table
and some object in the database.
Alright, of course we know
when you do a FetchRequest,
it can only return objects
of a certain kind;
an array of objects.
And so, this will
let you get it.
And, it's a very important
method to understand,
which is object to
the index path.
Okay, you send that to the
Fetched Results Controller,
and it will return
you a photo star,
or a photograph photographer
star
or some NS Managed ObjectStar,
which is the object that's
at that row, and then you
can pull out the attributes,
and put them in to
your UI-TableView cell
in self row index path.
Okay? It's really important
to understand that method.
How to you create one of these
NS Fetched Results Controller.
Okay, its Allocinit
looks like this.
It takes a FetchRequest,
a context.
That's obvious where we're
going to be doing the fetching.
Right? It will even do
section headers, so you specify
which attribute in the
objects that your the section,
the name of the section,
and then it will divide
the table into sections.
And, it can also do
caching, okay, so we'll talk
about those last two
things in a minute here.
But, let's take a
look at what kind
of FetchRequest we
might create to put
into a Fetched Requests
Controller,
so here I'm creating a
photo request, so I'm going
to be fetching photos.
I need a sort descriptor
that says what order these
photos are going to be
in in the TableView,
so I'll sort them
by their table, let's say.
And, then a predicate.
I'm going to get all the
predicates that were taken,
all the photos rather that
were taken by a photographer
with a given name, photog name.
Okay, so I just specify
the predicate.
So, you I just basically create
a normal NS FetchRequest,
and then I just do this fetch
results controller alec,
FetchRequest context,
section key name and cache.
It's as simple as that, okay?
Now, oh, yeah, so,
those last two items.
The cache by way, one
thing about the cache,
if you specify nil,
it won't cache.
Caching means that it will
cache the results of that fetch
between launching of your app.
In other words, it
will permanently,
you know, on disc, cache it.
This is not caching it member.
You know, it's always going
to do it in memory caching.
Core Data does that.
So, this will make
so between launches,
it has this result cached, but
if you set that to non-Nil,
okay, you better keep your
FetchRequest exactly the same.
If you change anything about
your FetchRequest, and come back
and try to use your
cache, it's going to fail.
So, this is only
really for TableViews
that have the same Fetch
Request all the time,
exact same predicates
or descriptors.
Everything's the same.
If you're going to use
that section key thing,
try and put sections in your
table, the sort descriptors have
to match up with
the section keys.
In other words, the
rows in the table,
the photos that you fetch, have
to be in the exact same order
that section headers would be,
and this is a normal
TableView thing, right?
The section headers
always have to be
in the same order as the rows.
Well, that's true here too.
So, almost always, your first
sort descriptor will be the
section key header, to make
sure everything is sorting
in the same order.
The Fetched Results
Controller also has a delegate,
and using that delegate, it
can watch what's happening
in Core Data, and
when something changes
that would affect
your FetchRequest,
it will change your table,
which is incredibly cool.
Okay, that means if
you added a photo,
and if it would have
matched your FetchRequest,
it will add a row to the
table, and you don't have
to do anything, because
it's watching.
It's using that NS
Object Managed Context,
objects did change radio
station, it's listening to that,
and it's changing it with
methods like this, okay?
So, there's really two things
to get a Fetched
Request Controller hooked
up to your table.
One is, you've got to use it
to implement all those
UI-TableView data source things,
and two, is you've got
to set its delegate,
and then use all these
methods to have it watch,
but we've made that
easy for you.
I've created a class called
Core Data TableView Controller,
and I'm going to make
it available to you.
All it does it those two things,
and you're welcome to look
at the implementation of it.
It's all pretty much
just one liners
that are just using the
Fetched Results Controller
to implement the data source,
and to do the delegate
business, okay?
And, the only thing
you need to know
to use Core Data
TableView Controller,
it has a property called
Fetch Results Controller
and you just set that to a
Fetch Results Controller,
and it will just work.
Nothing else required to do.
You just set that, and Core Data
TableView Controlled will then
use it to answer all those
data source questions,
and also it will
set the delegates
of the Fetched Results
Controller,
and make it so it watches
the database properly.
Okay? So, that will be
included in your homework.
You will definitely want
that for your homework.
I will be using that
in the demo today.
Alright, so speaking
of the demo.
This is a huge demo.
I may not get all
the way through it.
It covers some things that I
haven't covered in lecture yet,
and that's kind of
intentionally.
This is the only
lecture I really do that,
but I just wanted to kind
of show you some things
that I didn't really want
to spend lecture time on.
I might come back to these in
future lecture, but anyway,
there's a lot, lot
there to cover,
and you have these
slides in front of you.
Hopefully you can see
what the list there is.
I'm not going to back to
the slide, so coming up;
today's your last homework.
We have an instrument, which is
performance monitoring adjunct
to X code on Friday's
section, and then next week,
we're going to talk a little
bit about multitasking.
I say more multitasking, because
I'm going to do some of that
in the demo today,
and then we're going
to do some more advancing
Segway.
So far the only Segwaying
we've done is,
UI-Navigation Controller
pushed Segways basically,
and then also, we
talked a little bit
about iPad replace Segways,
where you replace the
entire detail view,
which is kind of a weird Segway.
We're going to talk about
some more kinds of Segways
that we can do as well.
And, maybe we'll get
to Mapkit next week
or maybe the week after.
Okay? Alright, any
questions before I dive
into this monster demo?
Okay, feel free to stop me.
A lot of time when I'm
demo, I'm typing away,
I'm not seeing you raise your
hand, so feel free to shout out.
So, I'm going to create a new
project here, and I'm going
to do single view application,
even though I'm going
to use Core Data, and I told you
that if you click on this one,
you can see some
generated Core Data code.
I'm actually going to use the
code that's generated here,
but I put it off into a category
of my application delegates,
so that you don't really
need to look at it.
I'll include it in the
demo, and you can see it.
But, for your homework,
you're going
to do your Core Data
stuff using a documented.
UI-managed documented, and
I'm not going to show that.
Because I want you to kind of
go through the process of trying
to figure that out for yourself.
So, I'm just going to create
our normal view single view
application like we usually do.
I'm going to call is Photo
Mania, and it's going
to be universal app,
although I'm only going
to use the iPhone version.
I'm only going to do the bare
bones of this application.
What this application is
going to do, it's just going
to query Flickr those URL,
the URL for recent geo
reference photo theme,
the same thing we
did for Shutterbug.
But instead of just
showing the photos,
it's going to show you
the list of photographers
who took those photos.
And then, you know, after this
demo, you could easily make it
so if you click on
a photographer,
it shows you the photos
by that photographer.
Click on the photo; use
the image view controller
to show you an image.
So, that's kind
of the application
we're trying to build.
We won't get all the way to
building those other TableViews.
We're just going to do
this main TableView,
but that's what this
is going to do.
And, the way it's going to
do that; the way it's going
to show those photographers
is kind
of a little bit different
strategy
than we saw with Shutterbug.
I'm going, in the background,
basically of my application,
be constantly querying
Flickr every once in awhile,
and getting more
and more photos,
and then just throwing them
into a Core Data database.
Okay, just throwing them
in there in the background.
Meanwhile, I'm going to have
TableViews that are going
to be looking at that data.
Looking at the photographers,
clicking on them,
looking at them, looking at the
photos, and that's just going
to be always be updating
automatically, all the time.
Okay, so that's the app
that we're going to build.
So, there's some things
to talk about here.
How to build a Core
Data database.
How to hook it up to a TableView
with the Fetched
Results Controller.
How to fetch things
in the background.
Okay? We're going to talk
about all those things
today if we have time.
Alright, I'm going to
call this Photo Mania.
I'm put it the developer
where I usually put things.
Here it is.
I'm going to dive right in
with building my data model.
My schema, as you would call
it in the database world.
This is a description of all
the entities and all that stuff.
We saw how to do this all
in the slide, so I'm going
to just going to show you
what it looks like live.
So, when I want to create a
new schema, I do new file.
Okay, so I'm going
to do new file.
I'm going to go up here to Core
Data, and pick this data model,
not mapping model, data model
right here, so click that.
We can call it anything
you want.
I'm going to call this one the
name of my app, photo mania,
and it's asking where do you
want to put it, and I'm going
to put it at the top level here
where all the rest
of my stuff is.
Here's my controller and
delegates something like that,
so I'll put this data
modeling file there.
And, so it creates this
data modeling file.
You can see it's empty.
I've no entities or
attributes or Fetch Properties
or any of that business.
So, let's just start
adding some.
So, I'm going to go down here
to the bottom, add entity.
Click that.
It added one, called entity.
I'm going to double
click, and call it photo.
So, I need photo, and I
display photographers too,
so I better add photographer.
Now one thing that's
really important
when you make a schema is
you want to put the entities
and the attributes in
there that support the kind
of UI you're building.
Okay, and that's
really important for you
to understand in your homework.
Okay, this homework that
I'm assigning you is pretty
straightforward, as long
as you pick a good schema.
If you pick the right entities
and attributes in the database,
it's just really easy to just
throw up tables of information.
If you don't, if you have
kind of the wrong schema
or just too simplistic of
a schema, you don't put
in a couple of attributes that
you need to make your UI work,
it can be like ah, how do
I get that information.
So, the schema is your slave,
you get to make the schema
however, you think it's going
to best support the application
that you're building, okay?
So, photo and photographer.
What kind of attributes
does a photo have?
Well, let's see, of
course it has its title,
and it has a subtitle.
That's that little
description from Flickr.
It has the URL of its
image from Flickr.
Probably has the URL of
its thumbnail as well.
In fact, we could even
store the thumbnail data,
which you're going to want to
in your homework, right in here,
put the data in, not just the
URLs, and also importantly,
photos have a unique identifier
that comes from Flickr.
Because when I get data from
Flickr, I don't want to be,
sometimes you click Flickr,
you get the same photo again,
and I don't want
to be duplicating
that in my Core Data database.
So, I'm going to look at
that unique ID from Flickr,
and make those unique in my
Core Data database as well.
So, I've added these, but
I've got to set their,
you can tab warning
here, or any error,
because I haven't set these.
If I click on this, you'll see.
Must have a defined type, so
we got to set a type for these.
These all happen to be
strings; all four of these,
but you could image
putting things like dates,
like for your recent
tab in your homework.
You probably want to have
some sort of last viewed date
or something like that.
That's perfectly
reasonable to put in here,
and numbers and all that stuff.
So, we'll just do that.
Photographers are
a little simpler.
They just have a name.
Okay, a photographer has a name.
That's a string.
That's about it.
And, remember I told
you we could look
at these entities graphically
with this little
button down here.
Here it is right here.
They're kind of smashed
on top of each other,
but I can pick them
up and move them.
And, you can see that as I move
one, it kind of makes space,
alright, keep them, and if I
have relationships between them,
it will keep those relationships
sensible as I move them around.
So, let's create a relationship.
What is the relationship between
a photo and photographer?
As we saw on the slides,
who took, basically,
so I'm just control dragging.
I'm holding down control right
now, and dragging from photo
to photographer, and I have
this new relationship created.
And again, if I move
these things around,
this things will stay
with, so let's go ahead
and give these relationships
names.
On the photo side, this is
the who took relationship,
and on the photographer
side, this is the photos,
and we can inspect
this right here
with this little guy
right here; the inspector.
And, we can see all
kinds of things
about our particular properties.
This is true for properties,
and also for relationships.
And, of course, we know
that this is a too many
relationship, right?
Because a photographer
can have many photos,
so we get this double
arrow here.
But, it's a two one relationship
here, because a photo,
only one guy took the photo.
And so, if you move
these things around,
it will keep this all
kind of looking okay.
Alright? So, now,
we've kind of set
up everything here that we need.
This is a pretty
simple application,
so we don't need
any more attributes.
But, in your application, you're
going to have at least one
or more two more entities
and some attributes on there,
and some more attributes
on photo.
So, I left with some work to do.
Okay, so now that we have
this, we want to be able
to access all this stuff
in our objective C
code using properties
and normal class syntax.
So, we're going to do this
thing we talked about,
which is generating
manage object subclasses.
So, I'm going to pick
the classes that I want.
I'm going to go here and say
create NS managed objects
subclass for photo
mania, and we'll do photo
and photographer, both of them.
And, we click this, says
where do you want them?
I'll put those also at the top.
I'm going to put everything
at the top level here.
And here, I have my photo and
photographer, and I can see
that photo looks okay.
It's got photographer who took,
but photographer,
not so much, right?
It's got NS manage object
for remove photos object.
This should really be photo
star, so I'm just going
to generate these things again.
Okay. And really, it's too bad
that it doesn't automatically
do this two pass generation,
but you end up doing
it yourself.
Get used to doing this generate,
because you're going
to do it a lot.
You're going to be
constantly adding entities,
changing attributes, like
that, and you're just going
to constantly be regenerating
these things, and it's going
to ask you to replace them,
and so don't be uncomfortable
about doing that regenerate.
It's a common thing
to want to do,
and so now we're winning here.
Okay, so we have
these nice classes,
and now we can use properties
to access all their attitudes.
My photo dot title to get
at the title for example.
But, as I said before, we might
want to add code, and I do want
to add code to photo here.
I want to add code
to create a photo.
Okay. To make so that I can add,
insert a photo object
into the database.
And so, I'm going to do
that using categories.
Remember categories is that new
objective C thing I was telling
you about, where we
can add code to a class
without sub-classing it,
so I'm going to add code
to this photo class, right here,
without sub-classing photo.
Okay, so I do that
with file, new file,
and instead of picking
objective C class,
I'm going to pick
objective C category.
And when I do, it's going to
say, what class do you want
to make a category on, I'm
going to make a category
on the class photo, and
I'm going to call it Flickr
because that's what
this method that I'm,
these methods I'm going to
add to photo are all kind
of hooking Flickr up to the
database, so Flickr seems
like a good name
for that category.
And, it wants to know where
I'm going to put them.
Put them in the same places
everywhere as everything,
and so here's my .H
and here's my .M,
and it's asking me what
do you want to do here.
So, the method that I want
to implement here is a method
that essentially takes
a Flickr dictionary
and adds a photo
object to the database,
and returns the pointer
to it to me.
Everyone understand what
I'm going to do here?
So, I'm going to call
this thing, photo,
make sure I pick the same name,
so that I don't get
sidetracked here.
Photo with Flickr info and
this is going be NS Dictionary,
photo dictionary, and
what else do I need beside
that photo dictionary to create
an object in the database?
A hook to the database.
Okay, I got to know which
database you want me
to add this photo too.
So, I also need in
managed object context,
NS managed object
managed context context.
Okay, and that's all I need;
just the Flickr information
and the context.
That's the place you want me
to create this photo,
and I will, okay?
And, I'm also going to have
another one here; because I know
that I'm going to be
downloading these Flickr photos
in big bunches.
Every time I call URL,
geo reference photos
or whatever it's called, I'm
going to get a whole bunch
of them, like a hundred
or 200 of them.
So, I'm going to have a
bulk load one that I'm going
to call load photos from
Flickr array, NS-Array photos
of Flickr NS dictionary
into managed object context.
Whoops, NS managed
object context context.
Okay, so that's just
going to bulk.
It's going to call this
basically repeatedly,
although that might not be the
most efficient way to do that,
and we'll talk about
that in a little bit.
So, let me implement
these two methods.
Okay, this is the
interface of my category,
and so here's the
implementation of my category.
Now, I can do whatever I want
to implement these, except,
I can't use any instance
variables,
so I can't have any properties
that are, you know, here,
so I have to implement them
basically in terms of photo,
if that makes sense that way.
So, this is going to return
a photo, so I'm going to say,
photo equal nil, and down here,
return photo, and in between,
I got to go find this photo
in the database, or create it,
or whatever it may be.
So, let's start with
asking the database,
do you already have this photo?
And, so how am I going
to ask the database
if the photo is already
there, and the answer is,
I'm going to try and fetch it.
So, I'm going to have a
Fetch Request, and it's going
to be a Fetch Request
into the photo table,
if you know anything
about it, or into photos.
It's going to return
photos, okay,
because I'm trying
to find this photo.
And then, the request
needs a predicate,
and what is the predicate.
Which photo am I looking for?
Well, I'm looking for the photo
whose unique equals the same
unique that is photo
dictionary right here,
so let's go get that.
NS-string star unique
equals, and we're going
to need our Flickr Fetcher
import, Flickr Fetcher .H,
so I'm going to grab
Flickr Fetcher .H
from the thing we did
before, which was Shutterbug.
So, here's Shutterbug,
and here's Flickr Fetcher.
I'm just going to dray that
whole thing right in here.
Alright, so now I have
Flickr Fetcher .H,
and inside Flickr Fletcher .H,
we can get the photos unique ID
with this Flickr photo ID.
Okay? So, I'm going to
go down here and say,
photo dictionary,
Flickr photo ID.
Now, I might want to do
value for key path here,
just in case this Flickr
photo ID might have dots
in it or whatever, Flickr.
You know, it might have dots
in it like the description has.
Okay, I'll leave
it this way here,
but value for key
might be a good idea.
So, I'm basically going to
fetch into the database to try
and find this unique photo;
see if it's already there.
And, I do that by saying
I need an NS error here,
and then I'm going to say NS
array matches equals context,
because we always have to
ask a context to do a fetch.
Okay? Execute Fetch
Request, that request,
and if there's an
error, return an error.
Okay? So, now I've
got those photos.
Those photos hopefully, in
this case a matching photo
or maybe not, has
been pulled out.
Now, this matches
can have a number
of different states
or different values.
One thing is, it might be nil.
If it's nil, okay, or if this
error is not nil, let's say
or error or another
error condition here is
that the matches, matches
count is greater than one.
Okay, because these are
supposed to be unique,
and so if I somehow got
multiple photos by doing this,
that would also be
an error condition,
so I have to handle error here.
Handle error.
I'm not going to do that
today, but you can imagine.
Okay, otherwise, if the
matches found something,
then we can just
return it, okay?
So, how do we return it?
This is in array, but this
array is going to have the one
and only one match, so I'm going
to say matches first object.
Could also say last object.
Otherwise, this matches
dot count is 0,
so it returned an
array, an empty array.
That means I looked for that
photo that had that unique,
I couldn't find it, so
that photo doesn't exist.
I now need to create it.
Okay, everyone remember how
to create an object
in the database?
NS entity description, insert
new object for entity for name,
we're inserting a photo,
and we obviously have
to specify the context.
Okay? So, we created a photo.
Excellent.
And, now, let's go ahead and
set the attributes of the photo.
I'm also going to set the
photo's unique, go to unique.
Alright, so here I'm
setting the photos title,
subtitle, image URL.
So here I'm just setting the
title using value for key path
out of the Flickr
dictionary, the subtitle,
given the description, the URL.
I'm using this URL for
photo format thing.
I have to turn it into a
string, okay, because can't URLs
in the database, but we
can put strings there,
and then I also have
the photographer name,
but I have a relationship
to photographer entity,
so now I need to create
a photographer as well.
So here, loading a
photo, right from Flickr,
is causing a photographer
also to be created.
Okay, and this is happen in
your homework too in spades.
Okay, where you're going
to download these photos
from Flickr, and you're going
to build your entire database.
Lots of entities are going
to be created all the time,
every time things come
back from Flickr, okay?
So, how do we create
a photographer?
Well, I'm going to do the
same thing I did here,
where I have this photo
category that creates that,
I'm going to do the same
thing for photographers.
I'm going to say new
file, another category.
This is going to be a category
in photography, photographer.
This one's not Flickr specific,
because photographer only
has a name, so I'm going
to call this category,
just to be different,
create, instead of Flickr.
Okay? So, we'll put
this in the same place.
Here it is right here.
Put this up here, and
Photographer, yeah.
It's very similar.
It looks almost exactly
the same.
We're going to fetch for it.
We'll handle, if
we can't find it,
set the name, all that business.
So, we put that in
the other file, okay.
Just trying to speed it
up a little bit here.
You wouldn't learn anything
new by my doing this all again.
Okay? But, now I have a way
to create a photographer,
given a name in a given context.
So, we'll use that over here,
and we'll just say photo.whotook
equals, and we've got
to import that little category.
Photographer create.
Photographer, oops,
photographer with name
and the name is the
photographer name that we got
out of the Flickr
thing, and same context.
Okay? Everyone understand
this method right here.
So, this method is going to, if
we give it a Flickr dictionary
from photo info, it's going
to give us back a photo object
in the database,
either by creating it
or by finding one that's already
there, and it will return nil
if it has a problem with it.
Everybody got that.
Okay. So, now that
we have this thing,
we have these nice
ways to access it.
Let's talk a little bit
about the TableView,
and how we're going to display
this stuff in a TableView,
and it's really a simple matter
of creating a new TableView
subclass that implements
that Fetch Results
Controller business.
And I told you that
you were going
to have this Core Data
thing to make that easy,
so we're going to use that.
Here is the Core Data
TableView controller.
We'll drag it in.
We'll take a look at it here.
Alright, so here's the
Core Data TableView.
Here's its header file.
You can see, it just has this
Fetch Results Controller thing.
It also has a way to
force it to Fetch,
but you don't ever
have to do that.
It will happen automatically.
So, it has this property,
and if you look
at this implementation
of this thing.
Besides setting the
Fetcher Results Controller,
which is mostly just a bunch of
logs, okay, that I put in there.
It's implementing UI-TableView
data source, you see,
in terms of the Fetch
Result Controller.
And then, it's also doing
this delegate business,
where it's watching for
changes in the database.
Okay, and that's it.
That's all it does.
And this code is
actually copied and pasted
from the documentation for
NS Fetch Results Controller,
so this is nothing
exciting in here.
So, when we create a
TableView that wants to look
in the database, okay, we've
created objectives in face,
we're going to make
it be a subclass
of Core Data TableView
Controller.
So, I'm going to create
one, and I'm going
to call it photographers,
I'm going to call it CDTVC,
Core Data TableView Controller.
Okay, it's kind of a naming
convention some people
like to use, and so
I'm going to do that.
Because it displays
photographer;
that's what it does.
So, let's create that.
Let's put it top level; same
place as everywhere else.
Here it is.
It's created it.
I don't need any of
this business for that.
And, let's think
about its public API.
What does this thing need?
Well, it needs what
most things need
that are doing database stuff.
It needs an NS managed object
context, and so, this class,
its job in life is going to be,
it will show you all
the photographers
in a given context,
the given database.
You give it a point or two
databases; it will look in there
and show you all the
photographers in it.
That's what this thing
is going to do, okay?
So, to make that happen,
all it needs to do is set
that Fetch Results Controller
thing in its super class, right?
Which is its Core Data
TableView controller,
so I'm going to do that.
As soon as someone sets
the managed object context.
Let's call this managed
object context,
so it's a little clearer.
As soon as someone sets
this managed object context,
I'm going to be able to set up
my Fetch Results Controller.
I can't set up my Fetch
Results Controller
until I have the context.
Sometimes, the context comes
to me via public API like this.
Some view controllers
will get their context
from other objects.
Most notably, and pay attention
here for your homework,
if someone gives you a
managed object like a photo
or a photographer, you
now have the context,
because NS managed
object has a method
in it called managed
object context.
It will give you the context
that that object
came out of, okay?
So, it's really important
to understand.
If someone gives you a photo,
you have a managed
object context,
but this thing is
at the top level.
It's showing all
the photographers.
We don't have anything yet out
of the database, so someone has
to tell us the context.
Which database to fetch
these things out of?
So, now I just need to say,
Fetch Results Controller equals
something, and so I'm going
to create a new Fetch
Results Controller.
Alec in it, and it's in it
has all these arguments here.
It needs a Fetch Request, okay.
Actually, let's, so we don't
get this kind of blackiness,
let's go ahead and make
all the arguments first.
It needs a Fetch Request,
because that's what it does
is hook up a Fetch Request
to something, and
so, this is a request
into the photographer table,
right, so we want photographer.
We're going to show
all the photographers.
The predicate for
this thing is nil.
What does that mean
predicate nil?
Predicate nil means all of them.
Okay? So, if you
say predicate nil,
that means give me
all the photographers.
And sort descriptor, yea,
let's sort these things.
Let's sort them by, let's see,
sort descriptor with key, well,
let's sort photographers
by their name.
Okay? Amazingly, you can
actually sort things by things
through relationships.
So, you can sort it be other
objects properties if you want.
But here, photographer,
we're going to have it sort
by its name, and yes, we're
going to have it descending,
and we're going to use the
selector here called localized
standard compare, okay.
Which is what we use mostly for
stings that are going to appear
when these interface, okay.
We need to close
our array there,
because this is an array
of sort descriptors.
We only need one, and
we could limit like,
for example we could say,
only give us a hundred.
We only want to see a
hundred photographers,
which would be kind of silly
because we are sorting
alphabetically,
so this would not make sense,
because we wouldn't get
to see the people whose names
unfortunately happen to be end
of the alphabet, but
we wouldn't do it here.
But, in other cases you would.
In your homework, you
very well might do that.
Alright, so now, we
have the request,
we have the managed
object context.
That's an argument to
this method is what we're
setting actually.
Here's the section thing.
We could make sections here,
but there's really nothing
in a photographer to do
that, so we won't do that,
and we're not going
to catch, okay?
So, that's it.
That's really all
that's required
to make this TableView
work, except for one thing,
which is that Fetch
Results Controller,
I told you it implemented all
the UI-TableView data source
things, but there's one
of them it can't implement
which is self row
and index path.
Okay, it doesn't really
know what attributes
of the object you want
to put in which parts
of the UI-TableView cell.
Right? The title, the subtitle,
it doesn't know those things.
So, we have to implement
that ourselves.
So, that's UI-TableView
cell, self erode index path.
You should be very, very,
very familiar with this thing.
It just looks like this, cell
equal, self.tableview DQ,
and well, these are
photographers,
so we'll call this
photographer cells.
We got to make sure you guys
are going to keep me honest.
Make sure I remember to
set that in the story board
when we create one of
these in the story board.
And now, I need the photographer
that is at this row and section.
So, I'm going to import
photographer first of all,
not create, .H. Okay, so
there's the photographer.
And, then I'm going to
say photographer equals,
and how do I do this,
photographer equals self.
Fetch results controller,
objected index path, index path.
Now I have the photographer
that's in this row, okay?
So, now that I have
that, I can do things
like text label.text equals
let's say the photographers name
of course.
Also, how about something
cool like this,
cell.detail text label
equals a string with format.
What if I wanted to put how many
photos this photographer has
taken, well that information
is readily available to me
in the database,
percent D photos,
photographer.photos count.
Okay, X code, shoot,
the way it does that.
Okay. Right.
So, I just go through that thing
that goes through that thing
that who took photos
relationship.
I just grab the photos side.
It's an NS set.
NS set implements count.
I got what I need, okay?
And, then let's return
this cell.
Okay, every one understand
this self erode index map.
Question?
>> Fetch Controller came in
from Core Data table controller
that was subclass?
>> Yes, this property spectral
controller is inherited
from Core Data TableView.
That's actually a good question.
Okay, so let's go ahead
and build our story board
while we're at this,
and while we have this
fresh in our minds.
So, here it is.
This is the kind of
default one that we got.
Let's get rid this.
We don't want this.
Let's go bring out a TableView.
So, here I'm just going to
drag a TableView out here.
I'm going to set it to be
a photographers Core Data
TableView Controller,
right, and then let's set
up our cell the way we want.
We want it to be
subtitled, because it's going
to have the photographer name
and then how many
photos they took.
We need to make sure that
its photographer cell is our
reuse identifier.
Otherwise, we're ready to go.
So, if we had stuff
in our database,
and we hit run right
now, this would work.
That's all we needed to do.
An incredibly small
amount of code to hook
up a table view to Core Data.
But, of course, we have
no data in our databases.
Nowhere in our code are
we querying from Flickr
or loading stuff in, and so I'm
going to use the opportunity
of our needing that to
introduce you for the first time
to your application delegate.
So, I've always been moving
down to supporting files.
Don't look at them, you know,
and show now I'm going show you
a little bit what's in here.
So, your application
delegate is kind of like,
it is watching what's going
on at the highest level
of your application.
It sees your application
has launched.
Okay. It sees that your
application has resigned being
the active application.
It sees that your application
is entering the background.
Okay, we know then
iOS, the apps,
when you go to another app,
they don't quit, they just kind
of move into this
background state,
right, so we can find that.
You can find it when you move
back into the foreground.
If you become the
active application.
If someone's quitting
your application,
you find that out as well.
So, it finds out all these
things, and we're going to learn
about those later in the
quarter, so I'm going
to delete all those now, but we
are going to look at this one.
This one is did finish
launching with option,
so here it's tell you your
application finished launching.
Okay? This is a great
time to do things
like kick off some Flickr
fetching or something.
Now, if I'm going to be
doing my Flickr fetching here
in my application
delegate, I need the context.
Okay, now in your
homework, you're going to do
that by creating a UI
managed documented.
But, here, I have a little
piece of code that I got
from that other template
that I was telling you
about that I'm going
to bring in here.
It looks like this.
It's a little category,
and it has this method,
create main cue managed
object context.
So, that's a managed
object context that attaches
to a database, the
database for this app.
This only has one luckily, and
gives me; it's on the main cue,
just like a UI document one is,
so this code can be similar.
And then also, I can save it.
Now, I don't need this save
context message for you
on managed document,
because it auto saves.
But, here if I create this
manage object context not using
a document, then
I have to do that.
So, this is, like I said,
the other way to do it,
which you're not going to do for
your homework, but I just wanted
to show you, I didn't
really didn't want
to show you the UI managed
document, because I wanted you
to figure that out on your own,
so we're going to
manage this one.
Okay, so I've added this.
This is a, you can see that
the photo mania app delegate
category, so it simply
added these two methods
to my app delegate, okay?
No, what I'm going to do
here is I am just going to,
first of all, let me
create some property.
So, this is some stuff that I
just created, some properties
that I need and stuff like that.
For time, I'm just going
to put them in here,
but as we use them,
I will refer to them.
But one of them I'm going
to use right here is this
photo database context.
So, I'm going to keep a
property in my app delegate,
which is the context that
we're going to be fetching into
and that we're going
to be reading out of.
So, I'm going to
set that right here,
photo data with context
equals self create, oops,
got to import that,
import photo mania MOC.
I'm just importing the category
header file that has that create
in that, so create main
cue managed object context.
So, again, you're going to set
this as well, but you're going
to set it from your
UI managed document.
So, now, I have a context,
and I want to start doing some
Flickr Fetches, so I'm going
to call another method here,
start, what did I call this,
star Flickr fetch,
I think, okay?
So, that's just going to
fire off a Flickr fetch
as soon as we launch.
Okay, we just launched.
Get this message gets
set to us when we launch,
and I'm just going to
fire off a Flickr fetch.
So, that's one of
the times we're going
to fetch is as soon
as we launch.
We're going to fetch some
other times, so we're going
to fetch as soon as we launch.
So, I'm going to go ahead
and put this in here
so we can look it, instead of
my typing it in line by line,
and this is something
where it's got some stuff
that I didn't teach really
in detail in lecture,
but you should mostly
be able to understand.
Mostly what this is doing
here is it creates a session,
so you know about URL sessions,
so I'm creating this session.
This session is a
little different
than the one we created before,
because look, it has a delegate.
You see that.
We didn't specify
a delegate before.
Okay, we had delegate nil.
And, why do we want a delegate,
and why are we making it so.
Well, that's because we
want these Flickr Fetchers
that we're starting
off in the background.
If they finish while our
application is no longer
running, we want it to launch
our application and tell us.
Or, if we're in the background,
we're not the application
the user is using right now,
and this URL Flickr comes
back with some information,
we want it to you know, make
us, wake us up a little bit
and let us process it.
Okay, so by doing this delegate,
along with a background
session, we can do that.
So, I'm going to show you
this delegate implementation.
So, I create this session,
and then I'm doing here
on start Flickr Fetch is
creating a task and resuming it.
So, this is the exact same
thing that we did before, right?
We had a URL session.
We created a download task.
The only difference is last time
we did with completion handler,
and we had a little
block that would happen
when the download came back.
Now instead, our delegate's
going to get called
when the URL gets
loaded and comes back.
Does everyone understand
the difference
between what we did before
and what we're doing here?
Okay, no completion handler.
Here, we're going
to use a delegate.
So, let's look at what
that delegate looks like.
It looks like this.
Okay, there are three
methods in it.
These three methods right here.
One is your file just finished
downloading, and here it is
as a local file,
so this looks a lot
like that completion handler,
and then, here's a couple
that we're not going to
use, like giving you,
this gives you some progress,
how many bytes its read so far,
if it does it in
chunks, and this also,
download sessions can get
interrupted and then resumed.
We're definitely not going to
talk about that, but anyway.
Now, you can see I have an error
here, okay, so what do we do.
So, this is what we would have
done in our completion handler.
And, all we're going to
do here is we are going
to get the context, our
little photo database context
that we set up there
and application did
finish launching.
We are going to download
those photos from Flickr,
so Flickr photos is this, which
you're very used to, right?
Data with contents of URL,
Jasson, de-Jassonize it,
grab the results out of that.
Okay. So, we're going
to do that little thing.
This needs to be happening,
you know, this is a local URL,
so it can be happening on
the main thread, no problem.
Now, we're going to do
something in this context,
and notice I'm doing
perform block.
I didn't do perform block over
in the photo creating one,
because it's kind of implicit.
I'm creating a photo.
Of course, I'm doing it on
that context, so whoever calls
that would want to do that
in perform block, and that's,
in fact, what I'm doing here.
I'm calling that
method we just wrote,
load photos with
Flickr data, okay.
We didn't actually write that
method, so let's look at that.
So, that's over here.
Okay, we have photo
with Flickr info,
and here's loading the photos.
So, how do we load the photos?
I'm just going to say, 4NS
dictionary photo in photos,
okay, so give me each
Flickr photo one by one,
and then self photo
with Flickr info,
photo in manage context,
context.
Now, this turns out to be
really an inefficient way
of loading those
hundred Flickr photos,
because every time I call
this, I am doing this Fetch.
So, if I want to load
a hundred photos,
I got to do a hundred fetches
to see if those are unique.
Okay, there are much
better ways to do this,
and one of your extra credit
items is for you to try
and figure out a
better way to do this.
Okay, and one way is to
look at the unique ID's
of all hundred photos,
fetch them all at once,
and see which ones
are in the database,
because you can get a
list of them back, right?
The ones that are in there,
and then one by one, you can go
and create the ones
that aren't there.
Okay, so that's one
way to do it.
Okay, but this cheap and simple
way is good for a demo, okay.
So, back to our app delegate
and now we have this load
photos with Flickr array.
Let's go ahead and import that
header file, which I do, oh,
maybe I called it
something different there.
What's the problem?
Let's see, yeah, I probably
called it something different.
Call it the same thing.
Here's my delegate, here it is.
There we close, I called it
[inaudible] Flickr, right?
So, that's going to
load all these photos.
Notice, I'm saving
my context here.
Okay this is a method, manage
object context was saved.
This is an error,
which I'm ignoring.
Don't really need to do this
for your UI managed
documented, but it doesn't hurt.
You can do it if you want.
This would not break
anything if you had a context
from UI managed document,
but mine's not,
so that's why I'm
explicitly saving here
after I load some
photos in, okay?
Okay, so that's cool.
So, let's go look at our tables.
What is our tables, public
API, managed object context?
We never set that.
Okay. We need to set this
tables managed object context.
Okay. When and how are
we going to do that?
We have this application
delegate.
It's kind of this global thing,
and it is managing this
global database, but it needs
to be able to communicate this
thing out to anyone who needs
to use it, and the way
we're going to that is,
whenever we set this photo
database context, we are going
to post a notification,
the radio station thing.
So, this is the first time
you're going to see how
to post an notification, not
just listen with that observer,
you're going to actually post
it right here, so let's do that,
and when you post a notification
you almost always 100%
of the time, want to create
a header file, so I'm going
to create a header file.
Just go here to header
file, C, C++ header file,
and that header file is
going to contain the name
of the notification, and also
the name of anything that's
in the user info,
for the notification.
So, let's go ahead and make
sure it's in the right place.
It is. I'm going to call this
photo database availability,
because that's what this
notification is about.
This radio station talks
about whether the photo database
is available, so I'm going
to create this header file,
and inside this header file,
I'm just going to
put pound defines.
One is photo database
availability notification.
That's the name of
the notification.
I'm going to call it this.
I can call it anything I want,
but I'm going to call it that,
and then also when the
notification goes out,
I'm going to include the context
in the radio station broadcast,
so the person can just get it
when they get the notification.
I'll do that with photo
database availability context.
And, I'll use the same,
well, just say context.
It can be anything
you want it to.
Okay, so this is going to be
the name of the notification.
This is going to be the key into
the dictionary of information
that comes along with the
notification, alright?
So, now, let's send that
notification, and I'm going
to do that every time we set
this photo database context.
Question?
[ Background Conversation ]
>> Oh, yeah, probably.
Good point.
Yeah, no equals there.
Thanks, very good.
This is just a pound
sign defined.
If it was a constant,
we wouldn't do that.
Okay, alright, so let's set
this photo database context,
so in the set; I think I might
have a thing for that actually.
Set photo data.
Yeah, I do.
So, here when we set this photo
database context, we are going
to post this notification.
And we do that using the NS
Notification Center default
center, post notification name.
We just specific the
name, which is this.
For this to work, we need to
import that photo availability,
photo database availability
header, okay?
So, we're just going to
post this notification,
and we're going to give this
user info along with it,
and these are info, it's just
a dictionary that has one key,
which is that context,
and the value
of that key is the context.
Okay. So, this is how you post
in the radio station model.
Any questions about that?
And now, I'm going to show you
listening to a radio station
without having to create another
method and all this stuff,
basically really
straightforward listening,
and who needs to listen to this?
Well, this guy does,
this photographer guy,
he needs to listen to it.
So, basically, as soon as this
guy awakes, and I might do this
in it with style, or whatever
the designated initialize is
for TableView, but I'm just
going to it in a wait for nib
for here, because we know
this TableView is coming
out of the story board.
I'm just going to say,
notification center.
First let's import that
availability thing.
So, I'm going to do NS
Notification Center,
default center.
Watch this.
Add observer.
Normally, we do it with a
selector and all this stuff.
I'm going to do a
block-based one.
I couldn't show you this before,
because you didn't know
block, but it's this one.
Add observer for name,
and we give the name,
which is photo database
availability notification.
The object is who can send it,
and I'll let anyone
send this to me.
It's going to be
the app delegate,
but it could be anybody.
The cue, I'm going to do it
on the cue that I'm on now.
That's what nil means, but I
could say NS Operation main cue,
or some other cue even,
but I'm going to say nil,
which means whatever
cue I'm on right now
when this is being executed,
using block, so I'm going
to double click here
to put a block.
Okay, and then that's
the end of that,
and what's going to
be in this block?
This is one line of code.
Self.manage object context
equals this notification,
its user info, photo
database context.
Okay. Sorry for the very,
very long line there.
I think it will fit,
yeah it will.
Okay? So, I'm getting
this block.
It's executed whenever this
radio station broadcasts,
and because I put this
user info of the context,
now I have the context,
and I just set my own managed
object context, and voila,
it's going to load this table.
Questions about that?
So, that's notifying both
on posting and receiving.
Alright, so now hopefully
it will work.
Let's go take a look at
this, and there it is.
Okay, now it went
really fast there,
because it actually
did the load last time,
but we just didn't see it,
so the database was loaded.
So, I'm going to show it what
it looked like to load up.
So, how do I clean this out?
Okay, how do I clean
my database out?
So, really watch this, okay?
If you want to get
rid of your database,
especially if you want
to change its schema.
Because if you change its
schema, and then you relaunch,
it's going to say
incompatible database type.
So, if you want to get rid of
it, just press the home key.
I also recommend
quitting in X code first.
Then press the home key,
hold down, press to hold,
you can do this on your
device too, and then,
you get these jigglies,
and then press the X
to delete that application.
That will delete the
entire application,
including the database, and now,
when I launch again in X code,
it is going to start up blank,
doing the Flickr Fetch
in the background.
When that manage object
content is filled up with data,
it magically automatically
appears in the TableView.
That's because that Fetch
Results Controller is watching
the context.
Okay? Questions.
[ Background Conversation ]
Yeah, let's go back
and look at that.
The question is where
did I set this user info,
this little user info right
here, where did I set that,
and that was when I posted
the notification here
in my app delegate, which I
did when I set the context,
which I did when I launched.
Right, so I launch.
Here's launch.
When I launch, I create
the context, you're going
to create it with U
unmanaged document.
I set right here.
This is the setter for that.
Okay, I set it.
Then I post it to
available to everybody else.
Okay? Question.
[ Background Conversation ]
Yeah, so the question
is, how can I make sure
that the view controller
exists, and is listening in time
to hear this, because the
application delegate is posting
this pretty early,
right after launch.
It's sending out this
notification, and the answer
to that is that's why I do this
in awake from nib, really early
in the view controller's
life cycle, right?
When it's first created, so
it has the maximum chance
of getting it, but
it's possible.
It's unlikely, but it's possible
that some view controller
you might create later
in time might need
it, and in that case,
you might need a different
mechanism, or you might need
to report or you might
need to pass it along.
Okay, a lot of times, we don't
want to use this mechanism
to give the context
to view controllers,
exactly because the view
controller doesn't exist yet,
until when this availability
happens, it's not even there.
So, there are other ways to
pass you manage object context
around, and you always want
to use those before
a way like this.
Okay, and I mentioned that in
the hints, so the homework is,
pass the manage object context
to a view controller that's
NS vector results controlled
in a sensible way in a
way that makes sense.
If you're segwaying to it, pass
it to it by preparing it, right?
You wouldn't want to rely
on something like this.
Okay. Alright, now let's talk
about loading our
database some more.
Okay, right now, we only
loaded our database on launch.
Here's the application that did
finish loading with options.
We load our database right here
and Flickr fetch that's it.
Okay? Well, that's
not very good,
that just means we only
get one batch of data ever,
when we launch our
app, we have to quit,
or have to relaunch
it all the time.
So, what about kind of
loading this Flickr information
in the background,
and we can do that,
but there's really two
different background conditions
to consider.
One is background, and our
app is in the background.
In other words, the user is not
currently using our app, okay.
They were using it, but
now it's in the background.
Okay, how do I fetch
when that happens.
Well, fetching there is kind
of limited by the system.
The system is not going let you
just go hog wild fetching things
when you're not the app
that the user is using,
but it will let you
do it sometimes, okay?
And, the way you can get the
system to kind of wake you up
and let you fetch
sometimes in the background,
every once in awhile, I don't
know, a few times a day,
who knows what, but sometimes,
it's using background fetching,
which is a multitasking
API, new for iOS 7.
So, I'm just going to show you
this as an example of what some
of the multitasking
APIs look like.
Now, the way you turn this is
on, is you edit your project.
You see this is my project
I clicked on up here,
and now you're going to go
to this tab right
here, capabilities.
So, I go to capabilities, and
there's a lot of capabilities.
This really kind of
gives you a feeling
of how we're only skimming the
surface of iOS, when you look
at all these things you can do.
But, anyway, we're going
to do this one right here,
background modes, and I'm
going to turn this on.
When I turn it on, there's
all kinds of background modes,
things that I can be allowed
to do in the background.
That is to say when my app
is not currently being used
by the user, and I'm going
to pick this one down here,
background fetch, and if I turn
this on, okay, background fetch,
then I will occasionally by
the system at its discretion,
send a message to
my app delegate,
perhaps even launching
me to do it.
Okay? And what is that
message that gets sent.
I'll show it to you right here.
It is called, we're
going to type it in.
Application, so you can look at
all the things you can receive
from your application.
There is just a billion
of them here.
See them, okay?
So, we'll cover some of
those, but not all of them,
but there's quite a
few of them in here.
But, the one you get when you
do this is this one right here,
perform fetch with completion
handler, okay, so this gets sent
to you, and it's
basically saying, okay,
I'm giving you an
opportunity to go do something
in the background, a fetch
or whatever you want to do.
Usually it's a fetch,
but you can kind
of do whatever you want here,
and the only responsibility
you have in doing this is
to call this completion
handler when you're done.
That's the only thing you
absolutely have to do.
If you don't call that
in a timely manner,
the system will grow tired of
you, and it will stop fetching.
It will stop sending
you this message.
So, more timely we respond to
this, the more likely it's going
to let you fetch
in the background.
Okay, so what are
we going to do here?
Well, it turns out,
all we're going to do
in here is start a Flickr fetch,
and then we're immediately going
to call this completion handler.
We're not done.
This fetch, we just started it.
It's going to take awhile to
come back later, but we're done,
as far as this background
fetch thing is continued.
Okay, getting the result and
doing all that, that's going
to happen at some other
time, but here, we're done,
and we have to, the argument
to this completion handler is
a UI background fetch result,
which is whether whatever you
did in here changed your UI.
Because if it did, we need to
update the little task switcher.
Okay, does everyone know what
the task switcher is in iOS 7?
It looks like this, okay,
here's the task switcher.
It lets you go through
and look at very apps,
if my apps are doing
anything here.
Let's launch an app.
Let's launch safari here.
Okay, so now I go into task
switcher, and here's Safari.
See how it's showing me
what's actually in Safari?
It's not really showing me
what's in Safari right now.
It's kind of showing me Safari
the last time I left Safari.
Or, if I get this
background fetch
and this completion handler,
I say UI background fetch,
new data, then it would
redraw that thing for me.
It would give me a
chance to redraw it.
But, I don't actually
have any new data.
I have no data here, because
I haven't gotten the data
from this yet.
This Flickr fetch has
not come back yet,
so it's not going
to do anything.
Okay? So, this is great.
This lets me occasionally
fire off a background fetch,
but when the data comes
back in, then what do I do.
Well, if I'm in the background,
none of these URL things
are going to get called.
Okay? Because I'm back-grounded.
Now, it's not strictly true
that these won't get called,
because what will happen is
if the URL returns while I'm
in the background, so I
started it in the background,
if it returns, I'll get
another application thing called
application handle events for
background URL session, okay?
And, it also has a completion
handler, a little different one.
Okay, so this is called whenever
things happen in the background.
Now, what's interesting
about this one is,
I don't actually need to do
anything in this one either.
Because if I implement
this method,
then these delegate methods
down here will automatically
get called,
and they already know how to
unpackage the data from Flickr
and put it in my database.
They already know
how to do all that,
but I still do have
this responsibility
for the completion handler
on this one too, okay?
Now, this completion handler, we
really do want to wait to call
until we've actually
handled this URL coming back
from Flickr.
Okay, this is handling a
URL coming back from Flickr.
So, now we're going to wait.
So, I'm going to
have to hold onto it.
So, I'm going to.
I have an instance variable
here, where I'm going to hold
onto this completion handler,
and here's the instance
variable right here.
Okay. It's a void.
It takes no arguments,
just properties.
All blocks by the way,
want to be copy properties.
Blocks want to be
copied into the heap
when you keep a handle to them.
Something to know.
So, anyway, all I need to do is
keep this thing, and then I need
to call this when I'm done,
so I have a method down here
that I use to do that with.
It's called Flickr download
tasks might be complete,
because I might have multiple
download tasks happening,
and so what I do here
is, I get all the tasks
that my Flickr download
session is doing,
that's what this method does,
and it has a little block
that gets called, because it
can't do that immediately.
Sometimes it takes a little
time to figure that out,
and then if there are no
download tasks left, right?
Not download task
count, then I'm going
to call this completion handler.
This Flickr download backload
background inclusion handler,
and say that I'm done.
Okay, so now I've
finished downloading it,
I've redrawn my UI, and I'm
calling the completion handler,
and this completion handler
doesn't have the little UI no
data thing, because it always
assumes that you're going
to update your UI, okay?
So, it's always assuming.
It's always going to
redraw when you do that.
Okay. So, let's see what this,
okay, to see what this is going
to look like, there's
a really cool way.
Well let's, okay, let's
do this two part here.
I'm going to run this.
Here it is right here.
You can actually
simulate fetching
in the background in X code.
So, I'm going back to X code.
Here's my UI.
Okay, I'm going to say,
from X code, under debug,
simulate background fetch, and
watch what's going to happen
to my UI, oop, I got
put in the background.
Okay. And it's doing a fetch.
It's going in Flickr.
It's downloading to Flickr
and doing all that stuff,
and actually if I went
like this when it was done,
I would see the results in here.
Okay, now that's hard for
you to see here, so I'm going
to show you another way
to simulate a background
fetch besides this,
so let's delete photo mania
so that our tables are empty.
You'll really be able to
see it clearly here, oops,
I should have quit X code first.
Put that in the step.
And, so what I'm going to
do here is there's a way
to launch your application
as if it just got launched
from a background fetch, and the
way to do that is edit scheme.
If you edit this little scheme,
the scheme is how
it's launching you.
In this case, it's
launching us in a simulator.
So, if you edit scheme,
and you go over to options,
there's this little switch here,
launch due to a background
fetch.
In other words, when I hit run,
pretend I just got launched,
because a background fetch
got sent to me, okay,
so that's what that means.
Now, normally, we're not
going to set that switch
and leave it set like that.
You can actually duplicate this
scheme, so I have the schema;
I'm going to duplicate it.
I'm going to call
it my BFF scheme.
That means background
Flickr fetcher.
It's my BFF scheme, and in my
BFF scheme, I'm going to have
that switch set, okay.
In my other scheme, if I go
back to this scheme and edit it,
that switch is not set, okay.
So, if I want to
pretend that's happening,
I go to my BFF scheme,
and I press run.
Now, when I run, see it
ran me in the background.
So, the other two things --
the other thing I really wanted
to show you here, which I
don't really have time to do.
Oh, actually I'll do it real
quick is, how about fetching
when I'm the foreground app.
What happens if the user
is currently using me,
and I want to fetch
periodically.
Okay, that's a totally
different thing.
To do that, we're going to
use a class called NS timer.
Okay, so I'm going
to put this here.
Once the database context
is available, then I'm going
to fire off a timer using
this NS timer method,
schedule timer with
time interval.
I want to do this one.
How often should we
do our Flickr fetch?
Well, it doesn't seem like
Flickr updates it more
than once every 10
or 15 minutes,
so let's do it every 20 minutes.
So, this is in seconds.
So, I'll do 20 minutes, and the
target is going to be myself.
In other words, every 20
minutes, send me a method,
and the method to send
me is start Flickr fetch,
and the argument.
And, no user info.
Sorry, this has to be a colon.
I'll show you why in a second.
And repeat, yes, so I want this
to just be every 20 minutes
at sending this timer.
Okay. So, why is this start
Flickr fetch here have
to have colon?
That's because this timer
when it sends its message,
it always has an argument,
and if I do start Flickr fetch
with the argument, it's the
NS timer that sent it to you.
But, in this case, I don't care.
I'm just going to
start Flickr fetch.
So, every 20 minutes, I'm going
to fire off this Flickr fetch.
Okay, so that's easy.
So, if you're in the foreground,
now this timer will not fire
when you're in the background.
It just will not fire, but
that's okay, because we have
that background fetching
thing firing it,
not as often, but occasionally.
Okay, but now all the time,
our app is getting new Flickr
information all the time.
Make sense?
Okay, so that's all
I wanted to show you.
Hopefully.
There's a lot of
information there I know.
We have background fetching.
We have foreground fetching.
You've got creating
the database model.
You got doing the categories
to create the adding things.
We got the TableView with
NS Fetch Results Controller.
I'm going to post all this code.
I'll throw some comments
in there tonight,
so you can remember what
all these things do,
and you'll be good to go.
Alright? Good luck
with your homework,
and I'll see you on Monday.
>> For more, please
visit us at Stanford.edu.
