[ Music ]
>> Stanford University.
>> Welcome to the lecture 14 of
CS193P for Fall of 2013 and 14.
Today I'm going to talk a little
bit about miscellaneous topics,
UI application and
network activity indicator,
and then I'm going to
follow up a little bit
on the demo we did last time,
then I'm going to continue
that demo, and we're
going to take Photo Mania
that we built last week and
we're going to make it work
on the iPad, and we're going
to add a popover segue to it,
because I talked about
popovers a couple weeks ago,
but I never showed you how to do
it, and you know, all this stuff
if I just tell you about it,
it's really not real probably
for you until I show you how to
do it, so we'll do a popover.
And then we're going
to dive into maps,
so I'll be doing the
lecture today on maps.
Hopefully, I'll get
all the way through it.
And then on Wednesday, I
will do a demo with the maps,
and also then on Wednesday,
I will demo some more segues,
especially the embed segue.
Okay? So that's what
we're talking about today.
So let's talk about a couple
of miscellaneous topics.
So UI application
is my first one.
What is UI application?
It sounds important.
It's not really that
important, we dive right
into using the application
delegate last week,
where we did things
like application,
did finish launching with
options and, you know,
handling background
URLs coming in,
and background fetching
and all that.
That was all in the
applications delegate.
So the applications delegate
is actually set by a property
on another object
called UI application.
So UI application, this class,
it only has one instance
in your entire application.
You get it by calling this UI
application shared application,
and there's really not a lot
of really interesting stuff
in this thing, you can go
check out the documentation,
but all the real stuff is
in applications delegate.
Alright? So it has a property
on your application
called delegate,
that gets automatically
set for you,
and then your application
delegate object,
which we did a lot
in last Wednesday,
that's where all the action is.
Okay? So you can check out
UI application if you want.
I did want to point out
one particular property
on UI application, however,
which is the network activity
indicator visible property.
This is a Boolean property.
If you set it to yes, then
the little spinner that shows
up on the status bar,
have you ever seen that?
When you're doing network stuff,
there's a little spinner that's
spinning, that turns that on
when your application is
the active application.
And this thing, you know,
it's Boolean, yes or no,
that spinner is either
on or it's off,
it's totally your responsibility
to turn this thing on and off.
It's a little bit difficult
to deal with because A,
it's global, it's in UI
application, so all the threads
in your application are all
using this same spinner,
and number two, it's a Boolean,
it's not like a push and pop
or a count, and so imagine
that you fire off a big
FLickr fetch that's going
to take ten seconds.
And you start the app,
this network activity
indicator, turn it to yes.
Then, in another thread, you
fire off a little FLickr fetch,
it's only going to
take one second, okay?
So it fires off, it turns
this on, one second goes on,
it finishes, it turns
it back off.
Now it's off, but the ten
second one is still running.
Okay? So that's bad.
So it's totally up to you,
unfortunately, to put mechanism
in your app for dealing
with that unfortunate
simplicity of API.
I'm sure, I mean, I don't
know, but I'm guessing
that Apple tried to put more
complicated API on top of this,
and it just didn't work for all
different kinds of ways people,
you know, are doing network
activity in different threads,
so they just kind of said,
okay we'll give you this
and we'll leave it to you.
But you should turn this on.
I'm not sure if Apple would
reject an application submitted
to the App Store that
didn't turn this on,
and did do network
activity, but they might.
Okay? And they'd probably be
within their rights to doing it.
Why do we have this thing?
Because a lot of users
might be on cellular,
and they only have 300
megabytes a month or something,
and they want to know when
apps are using that up, right?
So they want to see that
little thing spinning.
So that's why it's important
to turn this thing on.
Only when you're doing network
activity, this is not a spinner
for please wait, okay.
Your app first of all should
never be doing please wait,
because as we know, we do
everything off the main thread,
but this is just to tell them
network activity is happening,
even in the background
in my app.
Question back there?
>> Is there a reason
why I always [inaudible]
when you're doing
network activity
and doing that on its own?
>> Yeah, so the question
is can't iOS know
that I'm doing network activity
in my app and turn it on for me?
And the answer is, I'll be
it could figure it out most
of the time, okay, but not
100 percent of the time,
because when you do
a network activity,
you fire something off, maybe
you're doing that URL session,
things like that, I think
if you do the URL session
where it's actually happening
I bet they do turn it on,
or they might.
I really don't know
what they do,
but then the bottom line is they
can't reliably 100 percent do
it, so they're asking
you, you can do it here.
So, this is the best to my
knowledge, that's the answer.
Um, okay so that was
just a little aside.
So now, a little
follow up on our demo
that we did last Wednesday.
Two things that I want to
clarify and that I did clarify
if you downloaded the posted
code and read the comments,
one is, as I was
going through my demo,
sometimes I forget things,
and I did forget this one line
of code, which is you have
to send a message if you want
to get these background
fetches to happen,
to your shared application,
you shared your application
called set minimum background
fetch interval.
Okay? So that interval, and it's
time interval, it's the number
of seconds that is the
minimum between the times
that iOS will send
you the opportunity
to do a background fetch, right?
So you're in the
background, remember,
the iOS can send you a
thing, it says "Hey, wake up,
you can do a background
fetch if you want,"
and this says the minimum.
Now, this minimum, you
can't set it to one second,
it's going to wake
you up every second
because there's a UI application
background fetch interval
minimum and that's the
minimum you can set it to,
and so if you want to set it
to that, then you'll get woken
up as much as the system
is willing to wake you up,
remember that only the minimum.
It could take much
longer to wake you up,
depending on what's happening.
One thing about these
background fetches,
the system is quite smart
about when it wakes you
up to do a background
fetch, it's probably waking
up a whole bunch of other apps
doing background fetches too,
and doing it all at
one time because all
of this multi-tasking in iOS is
all about saving the battery.
Okay? Why, you might ask?
Can't I have four apps on
the screen at the same time?
Well that would be
a lot of processor,
a lot of network activity,
a lot of battery drain.
Okay? And so when an
application is in the background
and it's not running, we want
minimum battery drain going on,
so if it's going to wake,
and a lot of the battery drain
is not necessarily what your app
is doing, it's just
the fact that the phone
or the iPad is awake, right?
It's up and running,
it's OS is running.
So mostly the phone
and iPad are sleeping
when you're not using it.
Okay? So you want
it to stay that way.
So if you are going to
wake it up from sleep
and start using battery, you
want to get as many apps going
with their background
fetches and all at once.
Plus, there's a lot of very
battery intensive things
like the radio antennas, right?
The wi-fi and the cellular,
those things use power.
So if you're going to
do a background fetch,
you're probably going to fire
up the wi-fi, that's going
to use power, we'd better
get everybody who wants
to do a background fetch
doing it all at once.
So this is just a minimum.
Now, the reason I'm
mentioning this is
because the default is
UI background fetch,
application background
fetch interval never
which means you'll never
get background fetch,
so you definitely
need to call this.
It also, notice, means you have
to run your application
at least once.
Your user has to run your
application at least once,
and this gets called if you want
background fetching to happen.
Once you've called this, system
knows you want to do that,
you know, once you go to the
background, then after that,
the launch, then it will
not only wake you up,
but if you were to exit or
crash, it will fire you back
up once it kind of gets you
into the background fetch world.
Users might find that they don't
like your application running
in the background because
you use a lot of resources,
their battery gets drained
when they let you fetch
in the background, because
you're a bad background citizen,
maybe.
They can actually go into
settings and turn you off
when it comes to background.
Okay, there's actually a switch,
it says "don't let Photo Mania
or Shutterbug fetch
in the background."
Don't do it.
And if you set that off, then
you won't be able to do it.
And you can find out if
the user has done that,
using this property
in UI application called
background refresh status,
and it will return
the refresh status.
It actually has three
different states.
One can be you're good to go,
two can be the user turned you
off, third can be restricted.
What restricted means,
and you're going
to see this in various things.
You'll see this with
the map stuff,
restricted means you
can't do it, it's off,
but your user didn't
turn it off,
and they can't turn it back on.
Okay? Because they're
restricted in some way.
How would this happen?
Parental controls, for example.
It's possible in parental
controls to make it
so this app is not
allowed to run
in background mode
in parental controls.
Corporate environment.
A corporation might not want
to allow a certain app to run
in the background because of
what it fetches or whatever.
Okay? So you've got to check
all three of those states,
and if it's in that restricted
state, not just this thing,
but anything that's in a
restricted state like that,
you don't want to
say to the user,
"I want to do background
fetches,
but you haven't turned me on,"
because then they won't be able
to go turn you on, and
they'll be like, "What?"
Okay, they'll be confused,
so I just want to make--
this is a good opportunity
to talk
about those three states, right?
Okay, it's on, it got
turned off by the user,
and it's restricted, meaning
it can't be turned on.
Go ahead. Question.
>> [Inaudible] if I want to do
something in the background,
but I don't want to do a fetch?
>> So the question is what
if I want to do something
in the background,
but not a fetch?
And the answer is,
you can do that.
This background fetch mechanism
doesn't mean you can only fetch
on the network, you
can do other things.
But it's called background
fetch and all that, I think,
for a reason by Apple, is
that they're kind of implying
"this is kind of what we
imagine you're doing with this,"
so they don't really want you to
wake up and then just use a lot
of resources somehow
doing something else,
but you are allowed
to do something else.
There's no law that says
when the background fetch is
called you couldn't make some
mathematical calculation
or something like that.
As you can imagine,
what really would you be
calculating mathematically?
Kind of, when you wake up
in the background it's kind
of like you want to check what's
going on in the world, okay?
And we're going to talk
about checking things like
"where am I in the world?"
That's a different thing.
There's another mechanism
for that,
and we're going to
talk about that.
Yeah. Question?
>> Is there-- let's say our
Facebook or snapchat users
to know that like someone sent
you an E-mail or whatever?
>> So the question is, is
this what, you know, Facebook
or some social media app,
that you know people are
sending you messages,
is this what it's using to say
"someone sent you a message,"
>> [ Inaudible Comment ]
>> Yeah, the little notification
line, and the answer is no,
this is not what it's doing.
There's another mechanism for
that called push notifications,
which we're probably
not going to get
to talk about, unfortunately.
So that's how they're doing it.
There is a way to basically
have a user of an app sign up
and say, with the server
somewhere, saying "hey,
I'm willing to accept push
notifications from Facebook,"
and then the Facebook server
can send notifications,
little tiny JSON packets,
basically, to the phone saying
"Oh, here's a message"
or something like that,
and the message might be
this guy's got a message.
When you get those,
there's a way
to get woken up in
the background.
So it's a different mechanism
for waking up in the background.
However, if you're doing
something, let's say you're
in "Read It" or in Facebook, and
you have your little page up,
the last time you
were in Facebook
and you want that to update.
No one is sending you
a message, per se,
like not a Facebook
messaging thing, but it's just
like people are posting on
their wall, you're watching
or whatever is going on,
and you want that to,
when you go to the app
switcher, you want to see kind
of what's happening there.
Not in real time, but
kind of like...you know,
that's what this
would be great for.
So wake up in the background,
fetch the current contents
of the page, update it, now if
someone looks in app switcher,
they can quickly see "Oh,
I've got new stuff there!"
and they can go click and look.
You see? So it's different kinds
of things, but sending a message
and notification, that's
push notifications,
which we're not going
to talk about.
Good question though.
Okay one other follow
up from that demo is,
I kind of use a little
demo ware in that,
when we got the background
fetch, when we got a chance
to do a background fetch, I
called start FLickr fetch, okay,
just to make it a
one-liner there,
that was almost a conceptual
thing I was doing, just to kind
of say "Okay, we
can have a chance
to do a fetch, let's do it."
But actually calling start
FLickr fetch there would not be
good, and probably
would not work, okay?
And why was that?
That's because start FLickr
fetch starts a background
session, URL session, okay?
Background session meaning
it's the kind of URL session
that if the URL comes back
and you're not running,
you get a chance to handle it.
Right? That whole handle URL
background session other one we
looked at.
Those kind of background session
URL fetches are discretionary.
Okay? Meaning that the system
can determine, can decide,
if you're in the background, I'm
not even going to do that fetch.
Okay? So those are fetches
that generally you issue them
in the foreground, they might
complete in the background.
Okay? When you get a
chance to fetch, okay?
Because of this fetch thing?
You want to do that fetch right
there, using ephemeral session
like we did everywhere else
in Shutterbug and stuff,
ephemeral normal session.
Not a background session.
That way, it won't
be discretionary
and it will actually
do the fetch.
And since the system is saying,
by sending you this message,
"Okay it's your turn
to do a fetch,
I've fired up all the radios,
I'm ready to do some network
activity, go ahead and do it."
So the code that I posed
after lecture last time
is doing the right thing,
it's doing actual fetch,
so you can go take a look
at the background fetch
message that gets sent by iOS
and you'll see that I'm doing
an actual ephemeral fetch,
I'm not calling start
FLickr fetch.
I just want to make it clear why
that code was different there.
Question?
>> [Inaudible] like update
a UI in the background
so that the task manager
showed the current view?
How do we handle that in
terms of using the main queue
or not the main queue,
because we can't [inaudible].
>> Great. Great question.
Okay, so the question is
something's happening and I'm
in the background, and my
UI needs to get updated.
Like, a URL comes
back or I get offered
to do a background fetch,
I'm doing all these things,
and isn't there a problem
there because I need
to do all my UI in
the main queue?
That's the question, and
that's a great question.
But the answer is, when you're
running in the background,
you're not on a different queue.
That background just means
that you are not the app
that the people are looking at.
But every otherwise, it's just
like you're running
in the foreground.
You can draw, you
can do everything.
Your main queue is
running, okay?
When you get the
opportunity to run like this,
it's your main queue that's
running, so you can do graphics,
you can do drawing,
anything you want, right?
So the difference
between foreground
and background is not main
queue/some other queue,
it's am I the active app?
Am I not the active app?
That's the difference between
foreground and background.
Normally, when you're
in the background,
you don't get to run.
Your main queue gets
no cycles, because none
of your app gets any
cycles, okay, normally,
but then occasionally you'll
get the background fetch
or URL will come back, or
if you're a location thing,
like I was saying we
were talking about today,
you can get messages that
"Hey the phone has moved
to a new location," um,
you get a push notification
that I was talking
about earlier.
You know, Facebook
sent you a message.
Those things will wake
you up in the background,
and you can get a
little time to process.
Any time you're given
an opportunity to run
in the background a little, you
only get a little bit of time.
Understandably.
You can't sit there and
run for ten minutes, okay?
The whole point is
to kind of keep you
when you're not the app the user
is using, we want to keep you,
you know, not using
a lot of resources
so the battery doesn't drain.
Okay? So good question.
Yeah?
>> If you do happen to start
something that takes ten minutes
to finish, is the
system just going
to cut off your processor
to pause you or?
>> So the question is, what
if I get an opportunity to run
in the background here from
one of these many mechanisms,
and I do start doing something
that takes ten minutes.
What's going to happen?
And the answer is, the system
is going to just stop you,
your process is going to
stop, you're not going to get
to finish, and that will
create all kinds of bad things,
your user will be like
"what's going on?"
you know? And that's bad for
you if things will timeout,
if you're accessing the network,
all kinds of bad things,
so the answer is you don't want
to do that, and the answer is,
the system will not
let you do it.
Good question.
Alright, anything else?
Great question, this is a great
slide, because we basically got
to talk about multi-tasking
here.
Alright, so let's talk about,
continuing our Photo Mania
demo here, and like I said,
I'm going to make it into an
iPad app, actually I'm going
to make it a universal
app, okay?
Believe it or not, and this is
going to be a fairly short demo.
And we've kind of built so
much reusable parts here
and so much knowledge
that you have
that we can really quickly now
make these apps do much more
sophisticated things, and then
I'm going to demo a new thing
that you've never seen
before, which is how
to make a popover segue way.
Okay? This is a new kind of
segue way, we talked about it
in lecture, a few lectures ago,
but I never asked you to do it
on homework, and
I never demoed it,
so I'm going to demo it here.
Oh yes, okay, let's quit that.
Alright, so, let's
go run Photo Mania.
This is exactly the way it
was when I posted it, okay?
So this is the posting,
and you can see here,
this is the perform fetch,
and you can see how I'm just
doing a normal ephemeral URL
fetch, I'm not calling
start FLickr fetch here.
And this guy is not...how,
okay, I know how it is,
okay we'll deal with
iTunes when we get there.
Alright, so um, so anyway,
so this is exactly what
I posted last week, okay?
Last Thursday or whatever.
So what did this do?
Let's run this, just so we can
remind ourselves what Photo
Mania does, it's been more than
half a week, and there it is,
it just fetches in
the background,
and also when it launches, kind
of a bunch of recent photos
from Flickr, then it
basically makes a table
of all the photographers
who took the photos,
so these are all photographers,
not photos, photographers.
But we'd love to be
able to click on these
and see the photos by
that photographer, right?
But we can't because we never
put any segue ways in here,
we never did anything, and plus
our app doesn't work at all
on iPad, in fact, let's go
look at our iPad storyboard,
you can see it right here, it's
just this big blank screen.
So if I ran this on the iPad,
it would be a big, blank screen.
So let's get rid of that.
Now, I want to build my iPad
UI here, but I'm going to do it
in a way that I showed
you a little bit before,
but it's really powerful,
which I'm just going to copy
and paste it from another
app, because Shutterbug,
if you remember, had a UI on
the iPad that's very similar
to what we want in Photo
Mania, so I'm going
to go over to Shutterbug.
This is Shutterbug
as we last left it.
And if you look at
Shutterbug's iPad UI, this,
it's kind of almost
what we want.
Shutterbug just shows
the list of photos here,
if we could just insert the
list of photographers here
in the middle, we'd have pretty
much what we want on the iPad,
so I'm just going
to copy all of this.
Go back over here
to Photo Mania,
and I'm in my iPad
storyboard here, and paste.
Oops, I guess maybe
select all over here?
Okay, select all, copy,
over here, and paste.
Okay? So put it in here.
As usual it's a little
bit of a search party
to find anything,
oh, there it is!
So here is that Shutterbug
iPad UI.
And like I said,
basically I want to insert
in between the list
of photos a thing here
where I can choose
the photographer.
The same thing, the
thing I just showed you,
that we were running
in Photo Mania.
While I'm here in Shutterbug,
let's grab the image
view controller.
We're going to need
that obviously,
our storyboard uses that,
so we'll put that over here.
Copy that in.
And that's all we
need from Shutterbug.
So this storyboard is pretty
much exactly what we want,
there's a couple of minor
things we need to fix here.
One thing is we don't
want this list of photos
to be the root view
controller of our split view,
we want the photographer
thing to be that.
So where can we get our
photographer's table?
Well, we actually have that too,
that's here in our
iPhone storyboard.
That's what I just ran
and showed you, right?
This is the list, this table
if you inspect its identity is
this photographer's core data
table view controller, right?
So this is showing that
list of photographers.
So let's just copy this.
Put this in our...oops,
and where did it go?
Whoops? Er!
Sorry. Sometimes hard to
find all this, there it is.
Okay? Notice that
it looks really big.
That's because I haven't segued
to it yet, so it doesn't know
that it's going to be in
a master of a split view
and be inside of a navigation
controller like that.
So let's go ahead and put that
root view controller in there.
Where is it?
Okay so here's the root of
our navigation controller.
This thing is also
probably called Shutterbug,
let's change this to Photo
Mania or maybe photographers,
because that's what's
going to show
up in our root view controller.
So I'm just going to control
drag to the photographer's one,
and reset that to be the
root view controller.
Okay? So now, let's get
more space here, alright?
So now our API or our UI is a
little more what we want, okay?
We have this photographer's
thing here, and now we want,
if each time we click on a
photographer, one of these rows,
then we want to go
to a list of photos.
Alright? So let's do that.
I'm just going to control
drag from here to here.
And this is inside our
navigation control,
so I'm going to push.
Okay? Now we're really
getting close to what we want.
Okay? This is Shutterbug,
but that's okay, that's going
to be the title, we're going
to reset that title anyway.
And what is the problem
with this UI?
This UI is actually exactly what
we want except for one thing,
which is that if we
inspect this guy right here,
it is a just posted
Flickr photo CDTVC, right?
Because I copied
it from Shutterbug,
and that's what Shutterbug
shows, right?
The just posted photos.
So really we want this to
be something like photos
by photographer CDTVC, right?
Because we're going to click
on a photographer here,
and we want this to show the
photos by that photographer.
Does everybody understand
why I'm saying that?
So let's just set it to be
that, and we're going to have
to create this view
controller right here,
so let's just do that.
File, new file, the class,
it's going to be a core
data table view controller.
We're going to call it
photos by photographer CDTVC,
we've got to make sure this
equals this, because I just set
that to be the class in here.
So let's put this
- I'll bring that,
let's put this in Photo Mania.
Huh, that's kind of weird,
okay...alright put in there.
Alright. So here's
our new photos
by photographer core data
table view controller.
I'm going to not have you
distracted by all this junk,
let's get rid of all that.
When we create a new view
controller, what do we do?
We always kind of think of
what is this thing's API?
What's it's public interface?
So let's look at the
public interface of photos
by photographer, and probably
some of you are imagining
that what this is, it's
really simple, it's just going
to be non-atomic strong.
We need to pass the
photographer in that we want
to show the photos of.
So I'd better import,
import photographer,
and then I can have
a photographer.
Okay so this is basically our
public model, this is our model
and it's public, so if
someone sets this photographer,
we'd better show the
photos by that photographer.
So this is a table
that shows photos,
photographer determines
which photos we show.
Okay? Now before we go
off and implement this,
I'm actually going to go down to
our photographer's coordinated
table view controller.
This is the thing that shows
the list of photographers.
Okay? That I started off
this lecture showing you.
Hopefully you remember this
code from last Wednesday,
you can see that it's doing
a fetch to the photographer,
showing them by name, it's
fetching all of them right?
I'm going to put in the
navigation code to navigate
from this photos one right here,
this is the list of photos,
sorry, list of photographers.
This little segue right here.
So let's give that
little segue a name,
we'll call it the show
photos by photographer segue,
because that's what
it does, right?
When we click on a
photographer here,
it's going to show the photos.
And then let's go back
to our photographer's core
data table view controller
and let's do the navigation.
Now, I'm going to
show you something
that I think you should probably
do for your development process,
which is to start
use code snippets.
Now we talked about this in
one of the Friday sections,
so I'm not going to go over it
again, but I have a code snippet
that I've created, for
example, which is a kind
of generic table view
navigation code snippet.
So I start typing what I called
it, table view navigation,
and I'm going to hit return,
and it's going to put it in.
So put this code in here for me,
and this is fairly generic okay?
And what does it do?
Well, it does prepare for segue
and it also does did
select row add index path.
Okay? So this can work for a
table view that is the master
of a split view, and it
will also work for something
that it's just going to
segue via navigation control
or whatever.
So how does it work?
Well if we prepare for segue,
it just gets the index path
from the sender, which
is a UI table view cell.
You've already seen this code
before, so it's nothing new.
And then it calls this
prepare up here, and we'll talk
about what the prepare
does in a second.
And then the did select row at
index path, it does the trick
where it's looking at the detail
control of the split view,
if it's a navigation
controller it looks inside
for its root view controller,
and then is preparing that.
Okay? Everyone understand
what these two methods do?
Okay. So now we've got
to look at this prepare,
because this is the thing that's
actually doing the prepare.
So here's that.
And what this is going to do,
it's going to get the managed
object in the row on the table
that we're talking about,
okay, and then it's going
to check the class of the view
controller we're segueing to,
maybe it's going to check the
segue identifiers as well,
that's not going to be--
you know, did select row at
index path is not a segue,
so it's not going to
be applicable there,
but I check here and see if
there is a segue identifier,
and if there's not, then
I'd ignore this part.
And then I'd prepare that view
controller for being segued to
or if it's the detail of
the split view controller.
Okay? So this case, we
have photographers segueing
to photos, so let's see
what this looks like.
Well, the index manage object
we have here that we're going
to be looking for is a
photographer, so I'm just going
to replace this with
photographer.
Photographer.
Okay? Just getting my
object in index path
out of my fetched results
controller, you know what
that is, and then what kind
of view controller
are we segueing to?
Well, we're going to
be segueing to photos
by photographer core
data view controllers
that we just created.
We haven't done the
implementation of this yet,
but we know what his public API
is, to set the photographer,
which is exactly
what we would want.
So let's go ahead
and import that.
Import, m, import photos by
photographer, and then let's go
down here and check
that that's the class,
photos by photographer.
Okay, so now we know that
that's the class that we want.
Here, this segue identifier
we can check that here,
and if you remember, I
set it to be show photos
by photographer, right?
That's, everyone know
what that is, right?
That is this thing right here.
This little segue.
Okay. It's identifier is this.
That's got to match what
we're doing in here.
Alright, so we're
taking that, and again,
if we're doing the did
select row at index path case
where it's just the detail view,
then the segue identifiers can
be nil, so it's length is going
to be nil, and so I use length
there just in case to check
for empty string and nil
equally, either of them,
and I'm doing not, so if
there's no segue identifier,
then as long a we're going to
a photos by photographer CDTVC,
then we know we're going
to, what we're going to do.
Now, some people would argue the
checking this segue identifier
that you should almost
never do that.
Okay? Because if you're segueing
to photos by photographer CDTVC
from a photographer's CDTVC,
you know what you're doing,
you don't need a
segue identifier
to tell you what you're doing.
That's what some
people would say.
And I see that argument,
it's not a bad argument,
I even buy that argument
that really you only
when you segue identifiers
if for some reason you
had two different segues,
and we'll talk a little bit
later in this demo an example
of where you might
actually have that.
So one could argue just delete
that, okay, just get rid
of that entirely,
don't even check that.
And here we know that
this is a, if it's photos
by photographer CDTVC, photos by
photographer CDTVC equals photos
by photographer CDTVC, start,
VC, alright, so we have that.
So now we're going to
prepare this view controller.
Photos by photographer dot
photographer equals the
photographer that was
selected in our row.
Okay?
>> [ Inaudible Question ]
>> Uh, yeah, we'll
talk about that.
So the question is, don't
I have to pass the context
to this new controller?
And the answer is
yes, and I'm doing
that in this line
of code right here.
So let's go look at
photos by photographer.
So photos by photographer, it's
going to get this photographer.
What do we need to do in
photos by photographer.
Well, really the
main thing we need
to do is fetch the photos
by that photographer.
So let's go ahead
and look at that.
Every time I set
the photographer,
and you're noticing, by the way,
any time you have a public model
set, you almost always are going
to use the setter
to update your view
when someone sets your model.
That's kind of an obvious thing.
One thing I might do here,
by the way, is set my title
to be the photographer's name.
That would be a good
thing, right?
I'm a controller that's
showing a bunch of photos
by photographer, so my
title might want to be that.
But the real thing I
need to do here is set
up my fetched results
controller.
That's the main thing
that CDTVCs need to do,
is set up their fetched
results controller,
and then they just kind of
work automatically right?
So to save some time, I
have that ready to go here,
this is what it looks like.
Let me, I'm going to go through
every line of this, don't worry.
So first is answering
your question,
how do I get my context?
I need a context, I can't
fetch without a context.
And the answer is,
I'm just going
to ask the photographer
what context it's in.
Okay? Someone gave me a
photographer, and I'm going
to go find out what
the context is from it.
That photographer came
from some database,
I want to get the photos
in the same database.
Okay? So I don't need to
pass the context separately,
it comes along with
the photographer.
If the context is nil, so
either the photographer is nil,
or for some weird reason
the photographer didn't come
from a context, that's
impossible,
but mostly this will be
the photographer is nil,
then I'm going to set my fetch
controller results to nil,
that blanks out my table.
If you set your fetch
results code to nil,
then your table's
going to be blank.
Which I want in this case, if
someone gives me a photographer
with no context, or gives
me nil photographer.
But otherwise, I'm going
to set up a fetch request
for all the photos where my
predicate is who took equals
that photographer, okay?
Everyone understand that
line of code, hopefully?
If you started on your homework,
then you understand it.
And then I'm going to show short
the photos by the photos title.
So they're going to be
in alphabetical order
by the title of the photo.
So this is a property on
photo, if you'll recall,
and we're going to sort by that.
Use this kind of finder
like sorting order,
and then that's it.
I just create this fetch, self
dot fetch results controller,
it's got the request right
here that I just created,
and the context, which I
got from the photographer,
and I'm not doing any
sections, and there's no cache.
Any questions about that?
Hopefully everyone
understands that from last time.
Now, what else does this photos
by photographer table
need to do?
Well, not much else, okay,
by sending the fetch
results controller,
it's getting the results, but
it has to display those results,
so it has to do self
row at index path.
Okay? That's the one thing
that core data table view
controller cannot do for you,
because it doesn't
know what attributes
of the object you want
to show in the row,
so we've got to do that.
The other thing it needs
to do is navigation.
Because when I click on
a photo, I want to have
that image view controller
show its image, right?
So it needs to do
those two things.
But I'm not going to put
those in this class, okay?
Why am I not going to
put these in the class?
Because those two things every
core data table view controller
that shows photos wants to do.
Okay? Every single one of them.
So I'm going to create a generic
photos core data table view
controller that knows
how to do that.
Alright? And then I'm going to
have this class inherit from it.
So I'm doing this to really
emphasize because a couple
of you, a few of you, are
still struggling a little bit
with this concept of using
object oriented design
to build your controllers.
Okay, so we're going to
do it again right here.
So I'm going to create
a new controller.
Okay? It's going to be a
new core data view control,
it's going to be called photos,
core data table view controller,
and its job in life is to
show a bunch of photos.
Okay? So let's do that.
Let's find out what its
public API is, okay,
here's its public API.
This turns out to have no public
API because all you need to do
to make this thing work is hook
up fetched results controller
to any photo fetch request.
Okay? This thing is a core
data table view controller,
so it has this fetched
results controller thing.
As long as you set that
fetch results controller
to any photo request, then the
job of this class is going to be
to display it and let you
navigate from it as well.
Okay? Generic.
Work for any photos, you don't
even have to set anything except
for the fetch results
controller.
Alright, so let's look at
this guy's implementation,
pretty straightforward here.
Don't need any of this,
alright, so here we got
to just implement
those two things,
self row at index
path and navigation.
So let's look at self
row at index path.
Looks like this, table view,
self row at index path,
and of course, we'll
just get the cell.
Okay this code should be
very, very familiar to you.
Go to the table view,
we DQ, okay,
I'm going to call
this photo cell.
Now it's interesting,
this is a generic class,
and it's using photo
cell as it's reuse thing,
so I probably want to
put that information
into its public header file.
So I'm probably here going
to say use photo cell
as your table view
cells reuse ID.
Okay? That way anyone who is
using my class doesn't have
to go look at its
implementation,
they can just get
this information
from the header file and do it.
So let's make sure we do that.
Let's go back here, here's our
photos by photographer cell.
Let's see what its cells
reuse identifier is,
and the answer is,
oooh, Flickr photo cell.
Because we stole
this from Shutterbug,
and Shutterbug is
a Flickr thing,
whereas we are a
core database thing.
So I'm going to get rid of
that word Flickr, and make sure
that this is what it's
supposed to be, photo cell.
Okay? Everyone understand that?
So back to here.
So now I've got this
photo cell, okay,
what am I going to do with it?
Well, I need to get the photo
that I'm supposed to
show in this cell.
So that's photo star and of
course we need to import photo.
Photo equals self dot
fetch results controller,
object at index path,
the index path.
Okay? This argument right here.
This, hopefully, is
completely you understand this.
Now, I just need to
set the text label.
I'm going to set it's text
to be the photo's title,
and let's set the detail, the
subtext, the subtitle thing,
to the photo's subtitle.
And return the cell.
Okay? So you can see
that writing cell
for row index path
is pretty easy
when it's a core data table view
cell, because usually the object
in the row which
you can get one line
of code has what you
want, you just display it.
Okay? Now, let's talk
about the navigation.
I told you I have this generic
table view navigation thing,
I'm going to use it
again right here.
Okay? So it's the exact
same thing that I put
in the other one, I just have
to make sure this is appropriate
to what we're doing here.
So this is photos, again, so
the managed objects are going
to be photo star photo, okay,
so now I got the
photo out of the row.
What does this thing do
in terms of navigation?
Well, it will navigate
to an image view controller
and show the image.
Alright? So let's import
image view controller,
because that's what we're
going to be navigating to.
Okay? Get down here, kind of
class image view controller,
again I could probably
skip the segue thing here,
because if I'm navigating
to an image view controller
from this photos
view controller,
I almost certainly
want to show my image.
There's really nothing
else I might want to do.
So we'll just do that.
So image view controller IVC
equals image view controller VC,
and we just need to set
the IVC's image URL equal
to an NSURL with the
photos image URL.
The reason I have to
do this, of course,
is because you can't store
an image URL in the database,
we stored it as a string, so
this converts it into a URL
because image view controller
takes a URL as it's public API.
I could also do something here,
title equals the photo's title.
Okay? Because really the
image view controller,
since it only has an image URL,
it doesn't have enough
information
to set its own title, like the
other one did, the photographer,
this one-- this guy's
subclass that we created,
it knew how to do it,
but this one really can't
so we'll help it out
and set its title.
Okay? Everyone understand that?
So now we have this nice
generic photos showing thing.
Let's go ahead and
make our photos
by photographer inherit
from it, instead.
Photos CDTVC, photos
CDTVC, okay?
So now it just inherited
the ability
to do self row index
and navigation.
Okay, and it still
does the fetch itself.
So its the one determining
what photos show up,
it super classes the one,
putting them in the rows.
Everyone understand
what I'm doing there?
Okay. Okay, so that's awesome.
Everybody kind of knows how to
navigate, everyone knows how
to load themselves up, and might
be that's all we need to do?
Let's see if I can
remember anything else.
I think that's it.
So let's go see if
we're working.
Let's try this on the iPad,
because we just built...whoops,
let's do it on the real iPad.
We just built this, so let's
go ahead and do that and see
if we have any bugs,
things not working.
Maybe we didn't forget,
we didn't set some
of our segues right or
something like that,
so we can see what's
going on here.
So here it's Photo Mania,
so hopefully it's fetching
from Flickr right now into
this photography table,
and it is, that's very good.
So here, we have
photographers, right?
That's what Photo Mania does.
Shutterbug fetched the photos
and showed you the
photos titles,
Photo Mania fetches the photos
and then shows you
the photographer.
And we can look and see, some
of our photographers have
three photos, some nine,
so let's pick this
guy, he has nine.
Let's pick this guy,
he has three.
And we can click
on one of these.
Again, hopefully nothing,
this is Rio De Janeiro,
maybe we'll pick somewhere else.
No, there's no titles.
Uh, how about this one?
Nah, there's no titles.
Okay, we'll do Rio.
Hopefully Rio is not
going to do anything bad.
Here we go [chuckles].
There's Rio.
Oh, good! Not bad [laughter].
Okay, so there's our
image view controller,
so this all worked great.
So hopefully it works
here in porcher mode too
and it does seem to
be working there too.
Okay? Oh - there,
okay [laughter].
Okay, so that's that.
Okay? You guys all got that?
It worked perfectly.
So now we can quickly move on
to the next thing we're going
to show, which is we're going
to show how to put a little--
put it in landscape
mode just to show here--
so right above where this
duck's nose is, okay,
I'm going to put a little button
called URL, and when I click
on it, it's going to do a
popover, and in that popover,
it's going to show me the
URL that's showing here,
the text of it, you know,
http slash something.
Okay, so this is mostly to
show you how to do popovers.
So let's go back and see
how we would do that.
This turns out to be
quite straightforward.
So here we are, here's
our UI, and what we want
to do is add a little
button here that does URL.
Okay. So we're going to
drag this bar button item
into the bar here, and
we're going to call it URL.
Okay, so this is going
to be a bar button item
that when you click on
it, it's going to bring
up a popover here, a little view
or view controller that's going
to appear, overlapping
everything else.
So how do we do that?
And the answer for that is
that we create an entirely
new view controller.
Okay? A popup, a popover
segue is a normal segue.
You segue to a new
view controller.
So we're going to create a new
view controller that's going
to display the URL
that's showing here
in image view controller.
Alright? So how do we create
a new view controller,
you all know how to do that.
We go into here, we
go up to the top,
we grab a view controller
and we drag it out.
Okay? Now this view controller
is quite big, let's make it
so we can see a little better.
So here's our view controller.
So this is the view controller,
it's going to pop over.
Okay? And we then just create
a segue by control dragging,
so I'm holding down
control, and dragging,
just like any other
segue, and this is going
to be a popover segue.
So this is the first time
we've ever done popover.
Okay? So now once you create a
popover segue, you can now kind
of create this view
controller how ever you want,
it's a look, to pop over.
And one of the things you
might want to set it its size.
Because if this is
our popover size,
that's not going to be good.
It's going to cover
our whole screen,
that's going to be horrendous.
So display URL, we only
need it to be small.
And it's nice to have URL on
one line so it's not wrapping
because URLs have
all those slashes.
So let's try to make
a really wide one
that will hopefully
fit in one line.
So how do we change the
size of a view controller?
Okay? Because all our other
view controllers have kind
of inferred their size using
these simulated metrics right
here, you see this
inferred size?
But a pop up view, a
popover's controller is special
in that you can change its size,
notice that you won't be able
to do this until X code knows
that this is a pop up view,
popover view controller,
or at least knows
that this view controller is
going to be in a popover context
because of this segue right
here, this popover segue.
Once you do that, if you
go to your view controller
and select its view, self dot
view, then you can go dimensions
and these will be editable.
The width and height.
So, for example, we
could make this 600 wide,
and maybe 40 pixels high.
Okay? Which is probably a
pretty good looking thing.
So that means when we press this
URL button it's going to pop
over and be something like
that, that's pretty good size,
600 is the widest
they will allow you
to make a popover, okay?
So I think if you
specify more than 600,
it's only going to show up 600.
Alright, and you can make
it any height you want,
although obviously you
wouldn't want it too big,
cover up all content underneath.
It doesn't really make a--
a popover that would cover
up everything, you would want
to use a different
kind of segue,
a modal segue in that case.
So we have this, and then this
is just a normal view controller
otherwise, this little
view controller thing.
So we need to create a subclass
of view controller
to be its subclass.
So let's do that.
And what does this
view controller do?
Well, it's a normal
UI view controller.
And it displays a URL, that's
all it does, so I'm going
to call it URL view controller,
because that's what it
does, displays the URL.
Okay? We'll put it in the
place we usually put it.
Actually let's put it down
here, eh, somewhere like here.
What's it's public API?
Very simple, property,
non-atomic strong, NSURL, URL.
That's the URL it's
going to display.
Okay? What's its implementation?
Also really, really easy.
Let's get rid of this.
It's going, when
you set its URL,
it's going to update its UI,
now this is not a table view
controller, so we're going
to have to write the update UI,
also when it's view
did load happens,
also wants to update its
UI, don't forget this part.
Okay, when you have non-table
view, table view controllers,
this set URL might be called
before your outlets are set.
Okay? So update UI
might do nothing
because you have no outlets.
So if you want to do it
again, view did load.
This is very inexpensive to
do, so I'm just going to do it,
possibly twice, if
someone were to set this
and my outlets were set,
and view did load happened
after that, it might happen
twice, but it's very inexpensive
to update my UI,
so I can do that.
So we need to write update UI.
To update UI, we need a UI, so
let's go back to our storyboard
and give this thing a UI.
And what I'm going to do
for this UI is just drag
out a text view, so I'm
going to go down here,
find a text view right here,
we saw a text view from before,
so I'm going to put
the text view in here.
I'm going to line it
up, let's go ahead
and get its auto layout
going, so I'm going to reset
to suggest a constraints,
I'm going to check to see
if it did something good,
which, it definitely did.
You see that it's going
to stick to the size
of its super view, I like that.
Let's inspect the text view,
I don't want all this code,
I'm going to put like
http slash, slash,
www dot Stanford dot edu, okay,
in there, that looks terrible,
let's make it a little bigger.
18 point, that looks better.
Let's make it be centered,
let's make it be selectable
but not editable, so someone
could select this and then copy
and paste it into their
browser and look at it that way,
so that's good, we
definitely like that.
So that looks pretty good.
That's a pretty good
looking view of URL or UIL,
and so now let's go ahead and
wire this up to an outlet.
Notice that when I do that,
it's trying to do UI view
controller, why is that?
That's because we need to set
the identity of this thing
to be a URL view
controller, right?
This thought it was a
general view controller,
as soon as I do that, you can
see that now it understands
that this is a URL
view controller.
So I'm going to go
ahead and drag
to create an outlet
to that text view.
I'll call it URL text view.
There it is.
Normal ID outlet.
Let's go ahead and
go full screen
on the code here, like that.
And now we can do our
update UI, which is that,
let's just have our URL text
view's text be the URLs,
its path basically
and there's a method
in URL called absolute string,
which will return the
absolute path of that URL.
Sorry, self dot URL.
The absolute path as a
string, which is what we want,
because text is a string.
Okay? And we can do a
lot more fun things,
attribute a text view, you can
set fonts, colors, whatever,
but we're just going to do a
very, very simple update UI.
So now we have this URL
view controller, okay,
that we're going to segue to.
Right? This is a segue.
We are segueing...man, I should
put my doc somewhere else.
We are segueing from
this view controller,
which is an image view
controller, right,
to this which is a
URL view controller,
via this segue right here.
Okay? So let's go ahead
and give that segue a name.
We'll call it show URL, that's
probably a good name for it.
Okay? And let's do the
prepare for segue for this.
That's the last piece
we have to do.
So how are we going to
prepare for this segue?
It's a normal segue.
This image view controller
is where it happens, right?
That's where the UI is,
so that's where we have
to put the prepare for segue.
So we're going to do that.
Let's put it right down here.
So I'm going to put a nice
pragma mark navigation,
and I'm just going to do
void prepare for segue.
And so here, I'm
just going to say
if the segue's destination
view controller is kind
of class a URL view
controller, okay,
then I'm going to segue to it.
And yeah, I could also say if
the identifier equals show URL,
but for speed here,
we're just going
to go ahead and not do that.
View, controller, class.
Okay. So now I have the
URL view controller.
URLVC equals URL
view controller, uh,
the segue dot destination
view controller.
Okay? I've got the
URL view controller,
and I can just set the URL view
controller's image, or sorry,
URL to be my image URL.
I am an image view controller,
so image view URL happens
to be my model, right?
So I have it handy dandy, and
I'm just going to set that.
Okay? So now, I'm totally
prepared to segue to this thing,
so let's go ahead and give
this a try and see if it works.
[ Background Sounds ]
>> Okay, so let's
pick a photo here.
Let's pick a better one
than that, let's pick, okay,
let's go back to Rio De Janeiro.
Okay, there we go.
So what is the URL for this?
It's going to be
something Flickr URL.
So we click on URL
and it shows it to us.
Some farm, some server
farm at Flickr.
Excellent.
Now, this looks like, oh,
good, it's all working.
But actually there's
a problem here.
Watch this.
I'm going to press
the UR button again.
Oh, the smog is building in
Rio here, look at it, oh,
it's getting so you
can't even see.
What's happening there?
Actually, that segue is
happening over and over,
it's putting up more
and more popovers.
So there's actually four or
five popovers over the top
of each other, that's why it's
getting darker and darker,
because the popover
kind of darkens the rest
of the screen when
it puts it up.
So if I click somewhere else,
which is how you dismiss a
popover, it's slowly getting rid
of them all, all the way
back to the other one.
Needless to say, this is not
a great UI, for the user,
so we don't want this.
Okay, why is this?
How are we going to stop this?
Well, we're going to stop
this when this segue,
when someone clicks on URL,
we are going to check to see
if we already have a
popover up, and if we do,
we're not going to
do that segue.
So let me show you
how to do that.
So first of all, we
have to keep track
of whether this popover is up.
So I'm going to do that
by adding a property here
to my image view controller.
I'm going to make it weak.
Here's one of the first times
we've used a weak property
outside of outlets, okay,
but it's going to be
in UI popover controller,
URL popover controller,
and the reason it's going
to be weak is because I want
to use the weakness so that when
the popover controller is gone,
no one else will have
a strong pointer to it,
my pointer will get set to nil.
Get it? So now I'm always
going to know whether
that popover controller
is up, but I've got
to set it initially, though.
I've got to set this
thing to the popover
when the segue happens, okay?
So let's do that.
And how do we do that?
I said this in the slide, but
you're probably like "what?"
but now you'll see it,
which is this segue,
if this is a popover
segue, will be a subclass
of UI storyboard called UI
storyboard popover segue.
Okay? Popover segue equals
UI popover storyboard popover
segue, segue.
Now I could just do this, but
I'm going to be a little safe
and say if my segue is kind
of class UI popover storyboard
popover segue way class, okay,
then I'll get it,
then I'll do this.
I just don't like to do
casts like that without,
you know, checking first.
Although if I got to
here, it probably is going
to be a popover, but, you
know, it should be a popover,
but I'm going to check anyway.
And now I'm just going to set
my URL popover controller equal
to that popover segue's
popover controller property.
If you look at popover
segue, here's popover segue,
I'm going to go to its
documentation, okay,
for UI storyboard
popover, and you'll see
that UI storyboard popover
only has one property,
which is the popover controller.
Okay? So we're basically
getting the popover controller
from the segue.
It's a special kind.
Okay? So it's a little--
hopefully you understand that--
everyone understand that?
Question? No?
>> So it's the same as
destination view controller?
>> Um, it's not, this is not
the destination view controller,
this is the segue itself.
Okay? We're not saying
segue dot destination view
controller here.
>> Popover controller is
the same as [inaudible].
>> Okay, great question.
Is the destination view
controller, this thing,
is that a popover controller?
And the answer is, it is not.
It is a URL view controller.
Okay? Popover view
controller is another class,
not a UI view controller, that
controls that popover, okay?
So it is not.
So the segue is a
storyboard popover segue,
out of which we get
the popover controller,
and the destination
view controller is a URL
view controller.
Everyone got all that?
Alright, so now we
have a pointer
to this URL popover controller,
and it's automatically going
to get set to nil as soon
as it goes off screen,
because it's weak.
It's a weak pointer to it.
There's only one other
thing we need to do,
which is not do this
segue if that thing is up.
And I actually talked about this
in the lecture, how we do this,
there's a method in UI view
controller called should perform
segue with identifier.
Okay? And this is the system
asking, someone clicked
on something that's
supposed to cause a segue.
Should I do it?
And right here we're
going to say if the segue
in question here,
it's identifier,
is equal to string show
URL, which is what it is
in our storyboard, and this is
the reason why maybe we want
to check it here as well, okay?
I skipped over that demo mode,
but you know, if we're going
to check it here, we might want
to check it up here as well.
But anyway, we've got this, I'm
going to return, in this case,
so if it's a URL, then if I have
URL popover controller, then no,
do not perform this segue,
because there's already
a popover up.
Otherwise, I could just say
yes, but actually I'm going
to do something a little
trickier, I'm going to say
if I have a image
URL, then put it up,
otherwise, also don't put it up.
See what I did there?
Two reasons not to
put, do that URL segue.
If I don't have any photo
showing, then that's one reason.
Or if I have a popup already up.
Else, now this is interesting,
I have an else case here,
which is super should performs.
Okay? So if I am not
preventing it, then I'm going
to let my super class UI view
controller decide whether it
should do this segue.
Which it's always going to say
yes, pretty much, but...okay?
This should be return.
Okay? So let's see if that
fixes all our problems
[background sounds].
Alright, so let's
go back to Rio.
Here we are, in Rio, let's
click URL, excellent, URL again,
again, again, again, it's
not doing it, click away,
going to fix all our problems.
Okay? There is a subtle problem
still here, which I'm not going
to fix because of time, I
need to get to the maps here,
but if I go to portrait mode and
show the URL, watch what happens
if I click photographer
over here
to show those photographers.
Oh! The URL thing
didn't go away.
I thought if I clicked away from
it, it's supposed to go away.
And the answer is, if
you click in the same bar
that the URL thing is, then
it does allow you to click.
That's the thing in the
slides that I talked about,
called pass through views.
So this whole bar is part
of the pass through views,
and the real bad
thing about this is,
if I click on a different photo,
it's showing me a
different photo,
but it's not updating the URL.
So this is really bad.
So I'm going to fix
this in the code I post,
actually let's just fix it
right now, easier to show you.
I'm going to do this.
Whenever someone sets my
image to something new, okay?
Call set image, I'm going to,
in my image view controller,
I'm going to dismiss any
popover controller that I have.
Okay? So that way if
someone brings up that thing
on the right and they click,
at least I'll put away my URL.
Okay? I could actually
have some code here
that updated the URL view
controller and made it change,
that wouldn't be that hard,
I'd just keep track of it.
The only problem is then
that would be inconsistent
between this portrait mode
and this mode, because here,
when I'm clicking, if I had URL
up here, if I click over here,
it makes the URL go away.
Okay? Because over
here is now no longer
in the same bar as the URL.
So I want my behavior to be
at least somewhat consistent.
So I'll make it so that when
I click on something new,
it makes the URL go away.
Okay? Okay!
Nice big long demo, I will,
of course, post all of this.
Now you know how to do
popover controllers,
you should really
have a good handle
on using those core data table
view controllers by now, I hope.
Oh! I promised I would
do universal app,
look how easy this is, okay?
I'm going to do my
iPhone, here's my iPad,
I'm going to take this, copy
it, go over here to my iPhone,
get rid of this thing,
paste, okay?
Go back to iPad, get this image
view controller, which I need,
go over here, paste it.
If I can find space for it.
Paste. Alright there
it is, put it up here.
Just need to make
the segue to it.
Control, drag.
It's a push segue.
Boom. We're done.
Now iPhone will work.
Okay? You can come up
after class if you want
to see it working, but
that's all there is.
So a lot of times when
you're working on iPhone
and iPad UIs you'll
get one working
and then you'll just copy and
paste back to the other one.
Get that one maybe working
with some new feature,
copy and paste it
in the appropriate things
back to the other one.
See what I mean, you can kind
of go back and forth between,
pretty straightforward.
Okay! Back to the slides.
Here we go.
Lecture 14, there it is.
Okay. So we're not
going to get all the way
through the maps stuff
today, which is fine,
because I have a little bit
of time at the beginning
of the next lecture,
and then I'm going
to be doing the map demo
in the next lecture anyway,
so it will be kind of
fresh in your mind.
So any questions about all
that big demo I just did?
All sounds good?
Understandable?
Okay. Alright.
Map kit. Basically I'm going to
be talking about map kit here,
but before I talk about
map kit, I have to talk
about another framework,
which is a non-UI framework,
which kind of underlies
the map kit framework,
called core location.
So core location is a framework,
has a bunch of objects in it,
that have to do with where is
this device in the universe?
Okay? Where on the planet, you
know, where, in terms of GPS
or other factors determining
where it is, where is it?
Okay? Where on earth.
So, its basic object
is a CL location
that it concludes a coordinate
which is, you know, latitude
and longitude, altitude, okay?
Horizontal and vertical
accuracy,
we'll talk about why that's
important, time stamps, speed,
course, things like that, okay?
That's the CL location object.
This object has this very
important property called
coordinate, and that
is a C-struct,
CL location coordinate 2D,
and inside is just
CL location degrees,
which is essentially a
double, which is latitude,
and another one which
is longitude.
Okay? And then the
altitude is in meters.
Okay, so this is the basic
object in core location.
So the question is how do...oh!
sorry, let me talk about
accuracy, very important.
So when you get a location,
you got it in a certain way
that might have varying
accuracy.
If you got that location from
GPS, it could be very accurate.
If you got it by looking
at local cell towers,
it might be pretty inaccurate.
Right? It could be a
mile off, actually.
If you got it that way.
And there's ways in between.
On Stanford campus, you can
actually get it by using wi-fi.
It can look around, see what
wi-fi things are near you
and tell by that where you are.
Kind of scary, huh?
So it knows where you are.
And that works even if you're
indoors or whatever, so.
Now, it only works for public
wi-fi nodes, et cetera,
but at Stanford, these wi-fi
nodes are all well-known,
so it knows where you are.
And you specify this
accuracy using one
of this KCL location accuracy
constants, and so there's best
for navigation, if you want that
kind of accuracy, that's going
to use your battery
because it's going
to be constantly doing GPS.
So that would be only if
your phone was plugged in,
like you're in your
car, and it's plugged
into the cigarette
lighter or whatever,
or I guess they have USB ports
nowadays in cars, but anyway,
you would want power there.
Then there's best, which
is also GPS, but not quite
as power hungry, and then
all the way down using wi-fi
and these other things to
less and less accuracy,
but how ever the location was
found, it will also report
to you what accuracy it used.
Okay? Both in terms
of horizontally
and then altitude
wise, vertically.
Understand that accuracy
means power.
The more accuracy you ask for,
the more power you're
going to use.
So ask for the least accuracy
your application can deal
with so that you use as
little power as possible.
Very important point.
Okay, some other properties
there, I'm not really going
to talk about them, you
have the slides for them.
Obvious things, speed
is calculated
by seeing all the points that
you're moving through time,
and it can calculate your
speed, things like that.
So how do you get one of
these core location guys?
Okay? I want to get a
core location object,
it says where I am right now.
And the answer is, you
use this class called CL
location manager.
Okay? So you instantiate
a core location manager,
CL location manager, and
you're going to set some things
up about it, and then
you're going to tell it
to start telling you where you
are, and it's got a delegate,
and it's going to start telling
that delegate where you are.
So that's basically
how it works.
Now, you can simulate
where you are,
by the way, in the debugger.
With this little thing
down by the debug bar,
place where the pause and all
that, you can just simulate
where you are, you can even
add places that you are,
if you want to like have a
whole series of locations
that you want to check
running through to see
if your application is working.
So this is a really cool way
to simulate being somewhere.
Alright, so CL location manager,
how do we use this thing
to get our location?
You create it, you check to
see what hardware you have,
because every different device,
iPhone 4, iPhone 5, iPads,
have different hardware in them
for figuring out where they are,
and so you're going to check
to see what's available.
Then you're going to
add, set this delegate
to be any object you want,
and then you're going
to configure it for what kind
of location updates you want,
accuracy, things like that,
and then you're going
to start it running.
And it's going to start
reporting to you where you are.
So what kinds of location
monitoring are available?
There is accuracy
based reporting, okay?
So you specify an accuracy
and it will tell you
to that accuracy where you are.
Okay? There's updates
that you can get
where it will send you a message
only when a significant change
in position has happened.
Okay? Imagine maybe it's using
cell towers or something there,
or if wi-fi is fired up for
other reasons, it might be able
to be using wi-fi, right?
But it's probably
not going to use GPS.
Only when significant
changes occur.
You also have region
based updates.
Put a little circle around the
dry cleaners, when you walk by
or drive by, it will
tell you, "Oh,
you're by the dry
cleaner," okay?
So that's region.
So you can set up a little
region, circular regions,
beacons, we'll talk about those.
And then you can also
monitor your heading.
Okay? So which way am I walking?
Okay, so that might be using
a compass, might be using GPS,
just depends on what
the device has.
So the first thing I said was,
you've got to check
the capabilities.
So here's a whole bunch of
methods, I'm not going to go
through them for time reasons,
but you need to check
these, okay?
Because, for example, the user
might have turned off location
services for you.
Okay? So you've got to know,
you've got to deal with that,
either ask them to
turn it back on, okay,
there's this restricted
thing for this too.
Or whatever you want to do,
or do some different thing
in your app, if you work with
all those location updates
or whatever, you
might be on a device
that doesn't have the hardware
you need to do what you want,
so you need to all
check all this
when you first create
your location manager.
So then getting it, you
can ask a location manager,
"where am I right now?"
Okay? Kind of poll it?
We never do that.
We use this delegate thing.
So let's talk about how
the delegate thing works.
First, you specify the accuracy.
Okay? This is location manager
property, desired accuracy,
I showed you the
accuracies before.
Specify that.
And also you can specify a
distance filter, in other words,
until the user moves at least
this far, don't even tell me.
Okay? So if they don't
go at least 100 meters,
or a kilometer, don't
tell me about it,
so that saves battery too.
The chip, the GPS
chip in these devices,
especially newer
ones, really awesome.
A lot of this stuff that
you specify here gets loaded
into the chip, and the chip
by itself is calculating
where you are and whether
you went far enough and all
that stuff, and then
waking the phone back up.
The whole phone can sleep and
the GPS is still watching,
and so if you can tune these
to be as minimal as possible,
you will save a ton of battery
in the device, because only
that GPS chip will be watching,
you know, what's going on.
Okay so then you start
getting the updates
by just calling start
updating location,
and your delegate will start
getting sent messages based
on the accuracy and the filter
that you specify
for distance, okay?
What does that delegate
method look like?
Location manager did
update to location
from location, is
one of the ones.
There's actually some other
ones that you could get sent,
so you want to check the
documentation on this one,
but this is the basic one,
where it's saying "Okay,
I got a new location,
here it is," that location
of course will have
accuracy and time stamp,
all these other things in there,
and it just gives you
the fun location just
for your own convenience,
so you don't have to keep it
if you just want to see
the difference, okay?
So that's it.
It's quite simple, actually
to use this location manager.
It's also quite simple to
drain the user's battery
in about an hour,
okay, so be careful
and know what you're doing here.
There's a similar
API for heading,
for tracking the heading.
The delegate can report
errors, and this is one case.
A lot of times you see me
in my demos, I just say nil
for the NS error,
and I ignore errors,
and sometimes that's okay, like
if I'm doing a Flickr fetch
and if it fails, I just don't
care because I know I'm going
to be doing another
fetch in 20 minutes,
so I'll just let it fail,
although even there,
I probably want to check it,
and if it keeps failing over
and over, then I need to maybe
get the user involved, okay?
But here, you really
want to check the errors.
Okay, and again for time
reasons, I don't have time to go
through the details
more than just
that these errors can occur,
but there are certain things
you need to do in certain errors
if you really want to be a
good core location getting app.
Um, background, can you
get these location updates
in the background?
Okay, I promised I was
going to talk about this,
and I even have a
slide about it.
And the answer is, you can.
Okay? You can even sign
up to be the kind of app
that gets the location
manager will just run
in the background
normally, okay?
It's the same place,
remember when we went
and did the background
fetches, we had to go
to our project settings,
and we clicked that switch?
There's another switch
there that's just location,
and when you do that, you'll
start getting this, okay?
But that's really for apps
like, you know, a fitness app
where you're going off to do
a mile run and your phone is
in the pocket and it's
tracking your progress,
and you've tuned it to,
you know, coalesce things
and to keep track of it
and report it to you.
You know, when you
do a fitness app,
you can really drain
the battery fast.
So if you're doing a fitness
app, by the way, which don't do
that for your final
project, but,
if you're doing a fitness
app, for the real, for real,
then you really got to
know what you're doing.
So really investigate that
because you really want
to be low power, but you can
still do lots of cool things
when it comes to tracking
where the user's running.
However, running in the
background like that,
since it uses a lot of battery,
is generally only for very,
very, very, very
small number of apps.
But there are two ways to
get background notifications
about where you are, okay,
that are very low power,
and they're a little coarser
granularity, they're not going
to be running down the trail
telling me exactly where I went
on the trail, but they
are telling you kind
of where you are and are really
useful for a lot of apps.
So let's talk about the two
ways that you can get notified
in the background and
in the foreground, okay?
If you can get notified in the
background, then you're going
to get notified in the
foreground automatically.
Here's a way that background
and foreground, you
can get notified.
Okay? The first one is called
significant location change
monitoring, and you just
get a CL location manager
and you can say start monitoring
significant location changes,
and then when the user moves a
significant amount of distance,
you will get notified
via your delegate.
Okay? It's as simple as that.
And this works even if
you're in the background.
Even if your application
is not running.
You will get launched to be told
that the person moved
to a new space.
Okay? This is an awesome API,
okay, very power efficient
because it knows how to
manage tracking where you are
in an efficient way and
still super useful for you.
The only downside of it is
significant distance, right?
You have to be going
significant distance.
Question?
>> Do we have any control
over the definition
of significant distance?
>> The question is do we have
any control of the definition
of significant, the
answer is no.
So yeah, so when you get
launched in the background,
if you get launched,
like you're not running,
your application
did finish launching
with options thing will be sent,
but there will be a dictionary
there, and one of the things
in the dictionary will be UI
application launch options
location key, and if
that key is in there,
that means you got launched
because a significant
change happened,
so that's how you know, "Oh,
that's why I got
launched," okay?
Because of that key.
Okay? Another way to find
out in the background
is region based launch,
region based monitoring,
very similar,
except for here you actually
specify either a circular region
or you can also specify
a beacon, okay?
And I'll talk about
that in a second.
So you specify circular region
on the planet, you know,
coordinate, and then a radius
around it, and if the user goes
into that region,
you'll get notified,
your delegate will send a
message, or you'll get launched
if necessary, and
you'll find out.
Now, yes, there's a limit to
how many of these you can have,
I don't know what it is, 40 or
something like that, your app,
and but this is also
incredibly efficient.
So this is happening
at a very lower,
power-efficient level as well.
Okay? The circular region
is obvious to create,
you just create a
CL circular region.
The beacon is a little
more interesting,
and I don't really have time
to talk about the beacon,
but a beacon is basically
not a place on earth,
but it's another device.
It's possible to
write an application
that essentially is a beacon,
and it's broadcasting
all the time,
and if your app comes close to
it, you'll get woken up and told
that you went into the region
of that broadcasting device.
This is new for iOS
7, incredible.
Okay, I'm really interested
to see what people come
up with this technology.
Becoming a beacon
is, here, by the way,
is the delegate method
you get, did enter region
and did exit region,
and you'll get launched.
Okay? The beacon is becoming a--
sorry, I'm fast forwarding
here--
uh, yeah, regions are tracked by
name, that's because they have
to exist when you're
not launching,
there are maximum
monitoring distances.
Uh, okay so beacons.
To become a beacon, you need to
use the core bluetooth library,
it's not part of CL
core location library.
So you want to look up CB, core
bluetooth, peripheral manager,
and find out if you
want to become a beacon.
Like you want to be the
beacon, not detect a beacon,
but if you want to detect
a beacon, you use this.
You create a region, which is a
beacon region, CL beacon region,
and you specify it's special
identifier that identifies
that beacon, and it just
tells you when you get close,
it will even tell you how close
you are to the beacon, okay?
Are you near it, or far, or
right on top of it, okay?
So it's pretty darn cool.
So that's regions.
Region monitoring.
So both region and significant
changes will notify you
in the background.
So map kit, I'm going
to talk about next time.
And it is basically
a user interface
for putting these beautiful
maps, but obviously we needed
that core location stuff to
know about how to find out about
where we are, and where things
are, and stuff like that.
So we'll pick that
up on Wednesday,
and I will see you then.
