Tip:
Highlight text to annotate it
X
[ 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.