WWDC2013 Session 304

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Applause ]
>> James Howard: Whoops.
Good morning everyone.
Thank you all for
coming at 9:00 a.m. here.
I know that's a little
early for programmers
or at least it is for me.
This is what's new in Map Kit.
I'm James Howard.
I'm a software engineer on
the Maps Team and let's begin.
So, we have a lot to cover here
and I'm going to go quickly.
So, hold on to your hats.
Our first topic and the
one that I'm most excited
about is Map Kit on OS X.
[ Applause ]
>> We've also got some updates
to Map Kit for the new UI.
So, we're going to
talk about that.
New Perspectives: We've got
new ways to look at the Map.
We've got a 3D mode that
you can use in Map Kit
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and we've also got the ability
to span around the 180th radian,
so these change the way that
you can set the view port
on the Map.
We're going to discuss that.
There's new Overlays
Functionality in iOS 7 and also
on Mac OS X and there's
quite a lot of this.
There's a ability to put
overlays underneath labels.
So, if you have a polyline or
a polygon and you want to put
that underneath the
labeling on the Map
to enhance readability
you can do that.
We've got the ability to do new
tiled overlays so if you have
like a raster image pyramid and
you want to place that on top
of the Map you can do that.
We've got the ability to replace
the built-in Apple Map data
with your own data via overlays
and we've got a geodesic
polyline.
So, that's new to Overlays
Functionality and we're going
to get into that
in a little bit.
We've got a search API, so
this is for doing local search.
So, finding locations via a
query string we can do that now.
And we've also got
a Directions API.
So, with that outlined let's
talk about Map Kit for OS X.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Here it is.
We have an NP Map view
and an NSWindow running
on Mac OS X there.
And what are the features?
So, it's just like iOS.
We managed to get parody between
iOS and Mac OS X for Map Kit.
We've got basically
the same API.
So, we have MKMapView on OS X
and the difference between it
and iOS is basically just
that' it's an NSView.
We have all the same things.
We have annotations if
you want to put a point
of interest on the Map.
The Annotation views are NS
views instead of UIViews
but they are other
otherwise the same.
We've got Overlays so you
can put areas of interest
on your Map and we've
also got the Local Search
and Directions API,
so it's just like OS X
or just like iOS on OS X.
There are some small
differences in terms of the UI
so here we have a window showing
a MapView with Annotation on it.
One thing you can notice is
in the lower right there
there's a plus and minus
and a compass control so you
can use these to interact
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with the Map via a
mouse and you can show
or hide these with a API.
And we have this Map
data attribution label
in the lower left.
This is basically
what you have on iOS.
Don't, don't obscure this thing.
We need it there
for legal reasons.
And the finally the callouts
that call it that says,
"Hello World" there on the map.
That is on the side so it can be
on either the right or the left
where in iOS it's on the top,
but otherwise it has
the same functionality.
You can set a left
and a right view on it
and you can also set
a subtitle on it.
The other thing about this
is it's available for apps
in the Mac App Store so you have
to code sign it and you have
to put this entitlement on
it: com.apple.developer.maps.
And you can turn this on via the
Capabilities page in Xcode 5.
And the thing I'll say about
this is it's not on in seed one,
so you can-- we're not
enforcing this at the moment
but in the next seed we
are going to enforce this.
So, it's something you
need to be aware of.
And with that let's do a
demo and I'm going to invite
up Alexander Carlhian up
on stage to do this demo.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And you should give him
a big round of applause
because if it wasn't
for Alexander we wouldn't
have Map Kit on OS X.
[ Applause ]
>> Alexander Carlhian:
Good morning everyone.
My name is Alexander
Carlhian and today I would
like to give you an overview of
the main Map Kit APIs on OS X.
How many of you have
used Map Kit in iOS?
Good, so for you guys this is
going to sound like a refresher,
but for the other guys it's
going to be brand new APIs.
So, for today let's just pretend
I am a software developer
working for a coffee company
that own a few places in Paris
and I would like to extend
my existing application
to add MapView.
So, how do I do that?
Well, we can start with
something really easy,
just within Xcode we added a
new object called MKMapView.
I can just drag it into my
view, resize, simple right?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Just, let's just
run-- here it is.
I have my window
and my map view.
Good, so the next thing I
would like to do I would
like to add controls for
zooming, for compass and I would
like to set the region to Paris.
So, let's start by adding the
compass and the zoom controls.
So, this is pretty easy.
You can just set shows compass
and shows zoom controls,
set the property to
yes and that's it.
If you want to set the region
you need to set a coordinate
which is a long lat
and set the radius
to create an MK coordinate
region.
So, the coordinate is a
long lat and the regions is
in meters here, so
that's 10 kilometers.
And just set the region using
set region on the map view.
Let's run again.
So you can see Paris.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You can see the compass.
I can tilt pushing up or down.
I can rotate.
I can zoom in and
zoom out, good.
So, the next thing is to add
pin for each of my coffee place.
To do that I create three
instances of MKPoint annotation
by setting coordinate,
setting an optional title.
I do it for each
of my coffee place
and I can add the
annotations on my MapView
in a single call
using addAnnotations:.
Let's run again.
I can see now that I have my
three red pins on the map.
That's great.
That's great start.
Well, you know what I want
to give a distinct look
to my application so I like
to customize this red pin
to look something else,
something different,
remember that is a coffee place.
So, I'm going to add
an image to my project.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Silence ]
>> This image.
And I'm going to add a subclass
of my MKPinAnnotationView.
Called MyAnnotationView
and designated initializer
I just call super
and load the image and just
set the image and that's it.
You just need to set the image.
Next thing you need to do is
to actually tell the MapView
that you want to use instance
of your custom annotation view.
So, first you set the
delegate of your MapView
and you implement this
delegate method here.
-mapView:viewForAnnotation:.
Here you can just
create one more instance
of your annotation
view and return it.
Alright, let's run.
And you can see that the
red pins have been replaced
by my image, pretty easy.
Alright, so the next step
will be to add a callout.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
A callout is like a popover that
pops next to the pin annotation.
So to do that you in
annotation view you can call
-setCanShowCallout: and
set this property to yes.
Well, I've changed the image
to have a slightly
bigger pin image.
So, I need to adjust the
offset of my callouts
where the callout would
be anchored on the right
and the left by just
creating a point here
and setting the offset.
So, let's run.
If I click on a pin I
can see the callout next
to it with my title.
That was easy right.
Well, I would like to
customize this callout
to add accessory views,
maybe add a button,
maybe ordering coffee just
by clicking on this button.
So, as seen on the
documentation there is a right
and left accessory views
so I'm going to use that.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm creating a left button,
which is size 32 x 32 points.
Setting the title,
target an action,
same thing on the right is a
button and I set the target
and action to call either
the right click method
or left click method.
I click on run.
If I show my callout I can see
now that I have this new button
and if I click on it I can see
the action is correctly fired.
Well, it's not exactly what
I want for my application.
I would like to customize
this callout to be bigger,
to show something
a bit different,
maybe have a bigger button.
So, how do we do that.
That's something that you
guys have been asking for iOS
and in fact, it has
already been available
since the first mission
of the API.
Just you need to keep in mind
that annotation view is
just a subclass of a view.
So, an UIView on iOS
and an NSView on OS X.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, something you can do
is just to add a subview
when the pin is selected
and remove it
when the pin is unselected.
So, I will show you
how to do that.
First, I would like to display
an address inside this callout.
So, I'm just adding an
annotation model object here,
which is the subclass
of MKPointAnnotation.
That just going to hold
the address, no code,
but in the App Delegate I'm
replacing the MKPointAnnotation
with my own, MyAnnotation
instance inside the address
for each of my coffee
place here.
So, next thing I'm going to do
is to add a view that's going
to be displayed on screen
when I click on the pin.
So, this is just a
subclass of NSView,
just basic -drawRect:
to add a background.
The View Controller is
going to load the nib
and inside the nib I'm
just binding my annotation.
I will show you my annotation
title here and address
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and just add a button.
Well I now have a
custom callout so I would
like to disable the
default callout.
So, remember we enabled
it in the allocation view,
so we're just going
to disable it now
by setting canShowCallout to no.
And the last part is to actually
implement the -setSelected:
method on the annotation view
so next time annotation
view is selected is going
to call -setSelected:.
So, I can just call super
and when the pin is selected
I'm just going to set the frame
of my callout and
just add the subview.
Easy right?
And when the pin is unselected,
I want to fade my view
and remove my callout
from the MapView.
Something you need
to keep in mind is
that we are adding a view
outside of the bounds
of the annotation
view of the pin.
So, we need to override the
-hitTest: method to correct that
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and to allow click
to be propagated
to the button inside my callout.
So, I'm going to run
again one more time.
I click on a pin.
I can see my callout.
I can see the title address and
a button and if I click it fades
out and if I click
again on a pin et voila!
So, thank you that
was my MapKit on OSX.
[ Applause ]
I'm really thrilled by this
and I'm looking forward
to all your applications
using MapKit in OS X.
Thank you.
James.
[ Applause ]
>> James Howard:
Thank you Alexander.
So, just to recap
what did we see?
We saw how to add Map Kit
to a Mac OS X project.
We saw how to control user
interaction with the map view
by adding those zoom
and compass controls.
We saw how to add annotations
to the map both the built-in
MKPin annotation view
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with the red pins and then
the custom annotation views
with the coffee pins.
And then finally we saw how
to add a custom callout view.
So, if you don't like the
built-in one that comes
with Map Kit you need a
little more space or whatever
to show what you need to
show, you can do that.
And that lesson applies
equally well to iOS as Mac OS X.
So, that's Mac OS X.
Let's talk about
what's new in iOS 7.
So, we've got a new UI in iOS 7
and there's a new
look for Map Kit.
So, the first thing we've
done is we've updated
the cartography.
You can see what we had
on the left there in iOS 6
and what we have on
the right in iOS 7.
So, we've improved
the visibility
of the roads especially
the major roads there
and we've improved the
labeling quite a bit as well,
so you have quite a lot
more detail on the map.
So, we think this makes
the map a lot more useable.
We've also improved
the Hybrid mode
so that's the old Hybrid Mode.
This is the new Hybrid Mode.
I think it's also
a lot more useable.
And we've changed the pins; they
look a little bit different.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
They're a little-- they've
lost a little weight.
They're a little brighter
than they were before.
But the nice thing about it
is it's the same dimensions
as before.
So, if you were doing any
math based on the geometry
of those pins it's going to
be the same as it was before.
The other thing we've got
is we've got a new callout.
So, it's this white
callout now instead
of the black callout
we had in iOS 6.
We've got a new user
location view.
So, this is this white dot
with the colored center.
And if you've noticed
we have a new property
on UIView, which is Tint Color.
If you set that on an
MKMapView it will filter down
and effect the user location
view and also the callout.
So, let's talk about
New Perspectives.
We've got some new ways that you
can look at the map in iOS 7.
So, you can now span
the 180th meridian.
So you can do this
either via touch,
you can just start panning West
and pan over the Pacific Ocean
or pan East from
Japan and pan over it.
And you can also do this
programmatically via API.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, just to look at the code
really quickly how could you
do this?
One way you could do it is you
could set the centerCoordinate
property of the map.
So, we'll create a
coordinate at the equator
and the 180th meridian
and set that on the map
or you can set the
region on the map.
Again we'll set the center
of that region to the equator
in the 180th meridian and we'll
use 1000 kilometers both East,
West, North and South
as the delta there
or you can do it by a MapRect.
So, those of you
that are familiar
with our MapPoint system,
which is a projected coordinate
system, which is proportional
to screen points relative
to the zoom scale you
can do that with MapRect.
So, we have MKMapRectWorld
which is the MapRect enclosing
that sort of square
world that we have
in the projected
coordinate system.
But you can actually make
MapRects that intersect that
or go outside the bounds of
that and if you want to do that,
that's fine and set the
visible MapRect this way
and that will work.
So, all of these three things
I showed do the same thing
and so that's the screenshot
showed on the slide earlier.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The other thing you might
want to do is you might want
to enclose pins on the map.
So, suppose we have this
pin here in Sydney and one
in Honolulu and we say oh we
want to show both of these.
So, figure out what would
be the region to span those.
It's kind of a bit
of a weird edge case.
So here's the code to do it.
So, suppose we've got two point
annotations, one in Honolulu
and one in Sydney and
if you want to look
at the longitude value
for each of those right,
it's nearly 360 degrees apart.
So, if you just naively
said, "Oh,
I'm going to calculate
a longitude delta" right
by taking my min longitude
and my max longitude
and subtracting the two, you'd
get like you know 354 degrees
or something like
that, 356 degrees.
It would be way more zoomed
out than what you want.
So, we have introduced a new
API called showAnnotations
and it makes a list
of annotations
and it just does the
work to make sure
that those are enclosed.
So, you get that screenshot.
You like that?
[ Applause ]
Good.
[ Applause ]
Yea, it's a nice new
convenience that we've got.
We've also got 3D.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, you can view maps in 3D.
We've got the Space Needle
here that you can view
so you can view these
buildings that we've got.
It's on by default in iOS
7 and also in Mavericks.
So, if you make an MKMap or
you put it in your project
or you recompile your
project you're going to have
to create users to be able
to enter that via a gesture
on those operating systems.
And we've got a whole bunch
of APIs for working with 3D,
which I'm not going
to cover here.
You should go to the
session this afternoon
in Pacific Heights at 2:00 p.m.
and see everything about 3D.
There's quite a lot to know
and we've got a lot of new APIs
around that and it's just too
much to put in this session.
So, go to that this
afternoon to learn about 3D.
So, let's talk about
what's new in Overlays.
So, just to run it
down we've got a new
class MKOverlayRenderer.
This is used to draw overlays.
We're replacing MKOverlayView
with MKOverlayRenderer.
We've got a new facility for
putting overlays beneath labels.
So, as I mentioned in the
overview earlier this allows you
to put your polylines or
polygons underneath the labels
and enhance readability
of the map.
We've got a geodesic polyline.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
A geodesic is the shortest path
between two points
along a curved surface.
So, as this applies
to the Earth it's--
you know it follows
that shortest path along the
curved surface of the Earth.
Why would you want to use this?
Probably to show the flight
path that an airplane takes.
Airplanes usually
take the shortest path
between two points, not
always, but usually they do.
We've got MKTileOverlays.
So if you've got a
raster image pyramid,
you've got your own
map tiles and you want
to show those either
on top of or in lieu
of Apple's data we can do
that and that works in content
with our Map data
replacement APIs.
And the last point is
better performance.
We rewrote the Overlay system
in iOS 7, so it's going
to be faster and
work better for you.
So, let's get into it.
First topic, MKOverlayRenderer:
What I'd like you
to do is replace everywhere
you use MKOverlayView
with MKOverlayRenderer.
So we have a whole
new class hierarchy
under MKOverlayRenderer,
MKPolylineRenderer,
MKPolygonRenderer
and MKCircleRenderer
and MKTileOverlayRenderer now.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And so just switch
from MKOverlayView
to MKOverlayRenderer class.
MKOverlayRenderer
is lighter weight
because it's no longer a view.
We didn't really need
the viewness of it
and this is the only way to
do overlays on OS X as well.
So, find and replace
and fix your errors
and it should be
pretty straightforward.
The API is basically the same.
So, on the topic of putting your
overlays underneath the labels
we have two places
you can put them now.
You an put them above roads.
So this is going to be
directly above the roads,
but below everything else,
above the labels, above shields
that you see on highways, or
this is below shields you see
on highways rather, below point
of interest icons that are
on the map an so forth.
And there's
MKOverlayLevelAboveLabels,
which is what we
traditionally had
since I was formerly
introduced to overlays.
So, this is the overlay.
It's above everything except
for your annotation views.
So, just to show what
this looks like here,
get out of the way of the thing.
So, this is what we had.
This is AboveLabels and
then just go ahead and push
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that underneath and it improves
the readability of the map.
You can see the labels on
the streets and the point
of interest icons there; they
really stand out a lot better.
And just to go through this in a
little more detail this is how--
this is sort of how the map
is layered from the ground up.
So, initially we had the grid
and then we add in the base map.
So, we add in polygons
like parks
and so forth, bodies of water.
We add in roads and we add
in 2D building footprints
where those are available.
And then
MKOverlayLevelAboveRoads
so we'll go ahead and put this
polyline here on this road.
Then we'll add in labeling
so you can see those
point of interest icons.
The street labels and so
forth come in and they're
on top of the overlay.
And then we can add an
overlay above those labels.
So we'll put the circle in
their above the labels and then
if we were to pitch in the 3D
those 3D buildings they push
through and they
occlude the overlays.
And then finally we'll come back
to 2D and add an annotation view
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and an annotation view
sits on top of all of that.
So, that's the layers
of the map.
That's how they fit together.
So, in Code suppose we have
an MKPolygon represented
in presidio and we have
this new parameter here
when we add the overlay level.
We can just pass either of
those [inaudible] values there
and get it where we want it.
So, pretty straight forward.
So the geodesic polyline,
here's a screenshot
of what this looks like.
We have the blue line.
This is the shortest
path as the pixel flies.
[ Laughter ]
And then yea, and then the
red line is the shortest path
as the crow flies in
a very long flight
to Tokyo from San Francisco.
So, in Code how is this done?
So, suppose we have a
method here updateOverlays
and we're going to
create a geodesic polyline
from two points.
MKGeodesicPolyline is a
subclass of MKPolyline
so it works the same way.
We just create it with a list of
coordinates, in this case two.
We add it to the map and the
map's going to come back to us
and say give me a
renderer for this
and we just use a regular
MKPolyline Renderer
to show this.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And it has a line
with a strokeColor.
There's no difference
between the renderer
for regular polylines
and geodesic polylines.
So, the same thing there.
Next topic, MKTileOverlays
so this is a full replacement
tile set that I built.
I used Core Image and I did
like a CP atone filter and I did
like a grid behind it and
so forth and took some tiles
and built my own tile set here.
So, that's my take
on an old time map.
How did I do this?
Well, it's pretty simple to use.
The first thing you do is
you configure a template.
You're also, if you have these
tiles you have an image pyramid,
a whole bunch of tiles located
on the web server somewhere.
You have some addressing
scheme for it.
You fill out this template URL
and you have your
[inaudible] parameters
or whatever structure
you use to make this URL.
There's an X and a Y and a Z
addressing each of those tiles
and we'll go ahead
and those are things
that are in the braces there.
We'll fill those in and so
when you create a tile overlay
with that we're going
to take that template
and as needed we'll load tiles
from your web server
in order to display.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We can set this property
canReplaceMapContent to Yes
and in the case where
we do that it's going
to not load Apple
data or show it.
It's going to load
your data and show it
so it's a way you can use your
own map content using MKMapView.
And then finally we'll
add it to the map.
We'll add it AboveLabels because
we're replacing everything
and that's how it's done.
And then the map is
going to come back to us
and give us a renderer.
We return an
MKTileOverlayRenderer
and return it.
So, just to go into
a little more detail
about this what is the
coordinate system for this?
So, the way that it works
is it's a regular grid.
It's a square and it's
tiled from the upper left
by default though we
also allow you to tile it
from the lower left, so you
can set your origin wherever
you like.
Well, either of those
two places.
And it goes by powers of two
so you have zoom level zero,
zoom level one, zoom level two.
Here we're looking at zoom
level three, so there's going
to be eight tiles
in the X direction,
eight tile in the Y direction.
And then you zoom in,
zoom level twelve.
We have two to the twelve
tiles in the X direction
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to the twelve tiles
in the Y direction
and it's quite a lot more.
So, it is quite a lot of data.
It's not the kind of thing
that you're just going
to ship you know
in you app bundle.
If you want to replace the
entire world you're going
to have to have a web
server loading this
up so you load only the
things that you need.
And the other thing to say
about this is the tiles are
in this mercator
projection that we use.
You can use this
code the EPSG:3857
if you're using software to
like warp an image to match.
There's various ways
we can do it.
I've used the command
line tools that came
with the geospatial data
abstraction library.
It's an open source
toolkit for working
with raster geographical data.
I've had good success with
this in the past myself
and the other thing I'll say
about it, it's the same system
as a lot of like web mapping
parameters if you've used
like JavaScript frameworks
for showing your own tiles.
It's the same system as
that, so you may be able
to use the same tiles
in Map Kit as well
as what you use on the web.
And on the topic of replacing
Apple data with your data,
so we do this either by
optional method on MKOverlay.
So, you can make--
if you don't want
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to use MKTileOverlay you
can just use any MKOverlay,
implement this method,
return Yes.
And what we'll do is
within the bounding MapRect
of that we'll say okay
we're not going to try
and load any Apple Map data.
We're just going to load
your data, so you'll see grid
until your data comes
in and draws.
And then it's also available
as a settable property
on MKTileOverlay.
And as I mentioned neither load
nor draw the Apple Map data
when we do this.
And you typically
use it above labels,
so you're showing this right.
We're not showing labels.
But one new thing is you
actually can put it above roads
and what we'll do in that case
is just load the data necessary
to display the labels.
So, if you had satellite data
or whatever that you needed
to display or something that's
not labeled and you wanted
to have like a hybrid mode,
you could use this to do that.
So, I'm going to walk over
here to the demo machine
and show you a quick demo.
And what I'm going to do
actually is recycle a demo
that I showed in 2010, but
I'm going to update it.
Switch here.
[ Silence ]
>> Let's shut this down and
let's bring up a new demo.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Silence ]
>> That bigger.
So, I wrote this three years ago
for Worldwide Development
Conference.
Did you guys ever look
at Code three years ago?
Yea. What I'm going to do is
open my notes here and this--
the thing about this,
let me just build
and run it and see what it does.
I took this map and I'm
going to zoom in on it here.
I got this from the
National Oceanic
and Atmospheric Administration's
website three years ago
and I cut into the tiles using
GDAL and I have those tiles
in my apps resources here.
You can see them.
It's the thing that's
sliced up into tiles.
All of these guys are in there
and what this thing does it
just goes ahead and loads them
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and displays them in
semitransparent fashion
on top of satellite tiles.
So, this is nice, but the thing
about it was there was kind
of a lot of code to do this.
I'm not even going
to bother with it.
Just scroll through
there, it's a lot.
And there was more in there.
And it was kind of
complicated and the thing
about this is it only works
for pretty much this sample.
It's like well if you had
a small amount of tiles
in your app you're going
to say okay it works,
but it doesn't work
well if you want
to load them from a web server.
I kind of handwaved
that three years ago.
So, we're going to make that
better and the way to do
that is I'm just going
to delete everything.
[ Laughter ]
Just delete, delete,
this-- all this.
I'm just going to,
nope, nope, nope.
Gone. And instead, what I'm
going to do is I'm going to drag
in a new viewDidLoad
and what I'm going
to do is I still have these
tiles in my out bundle.
It works for me because
I don't have that many.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm not going to put
them on web server here,
but you certainly could.
I'm going to set up a template
URL so file URL for this.
I'm going to make a TileOverlay.
I'm going to say
geometry flipped
because the origin
is in the lower left.
I'll add that overlay to
the map and I'll release it
because it was three years
ago and we didn't have ARC.
And we'll have renderer for
overlay, new method here.
for overlay.
We'll make a
TileOverlayRenderer,
set the alpha on it to point
6, return it, build and run.
There we go exactly the
same thing and 20 lines
of code instead of 200.
[ Applause ]
Thanks. So, let's
shut this down.
Close that, close that.
So what did we see?
We saw that the tiles can
be bundled with the app.
So, in this case we had
a smaller number of tiles
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and we wanted to put
them in the apps bundle.
That's fine or more
likely you're going
to have a web server
serving up all of thse tiles
so you can download
them from your server.
And the other thing to see
as a I mentioned we can
replace Apple's Map Data
or we can show a topic if
we want to blend data on top
or we want to add
Apple's Map Data we can do
that using MKTileOverlay.
So, that's that.
Let's talk about Local
Search, enough of Overlays.
So, in Local Search
we've got the ability
to find a specific
place by name.
So if I search for Mascone
Center West and find that.
We can find a list of places
by type such as pizza places.
So, this is pizza places near
here or you can find an address.
So, if you want to find one
infinite loop Cupertino,
California.
You can find that; that's
Apple's headquarters.
We introduced this
in iOS 6.1 actually,
so it came out last fall.
We also have it on Mavericks.
And I would just like
to take a moment here
and compare this with Geocoding.
So, we introduced CL
Geocoder a few years ago.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And Geocoding is useful
and does something similar
but not quite the same.
So, I just want to explain
why you would use one
and not the other.
So, with Geocoding we have the
ability to reverse Geocoding.
So this takes a coordinate.
You have a latitude
and a longitude pair.
You get an address,
a structured address.
You can add to address book or
you can format it and display it
to the user if you want.
So, that's how this works.
You drop a pin, find
the coordinate for that,
reverse Geocode it, put the
address in the subtitle.
Forward Geocoding
takes an address.
You have an address
book card and you want
to find the coordinate.
So, in this example we'll
use the Maps app here,
open up our contacts list, find
a contact, find the address,
we'll Geocode that,
put a pin on the map.
Local Search takes a
free form query string,
so this is something
the user types in.
I want to find you know
a user UI search bar
and a search field, get back
a list of search results.
So, search for coffee,
drop the pins.
And those search
results are represented
by a class called MKMapItem.
We've had this around
since I was 6.0
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and its got a coordinate,
it's got a structured address
so you can add it
to address book
and if it's a business
we may have its name,
its phone number and its URL.
So, those may be
available depending
on what the search result is.
So in Code how this is done is
you create a request object.
So, MKLocalSearchRequest and
you set two things on it.
First is the query so this
is what the user typed
in in the user's language.
This is a query and
then the region.
So, it's important
to set that region
because if you don't
set it and you query
for pizza you're not going
to get relevant results.
So, if you have a map view
that the user can position
or you have some other way
of constraining you know
what the search is going
to be you need to set
that region in order
to get relevant results.
So, once we've got that set
up we'll create a search
object, MKLocalSearch object.
We initialize it with a request.
It's one local search
object per request.
However, you can create multiple
requests, multiple searches
and run them in parallel
if you want.
So, once we have that
we'll start it up
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and we'll specify a
CompletionHandler,
which is going to get either
a response or an error.
This is called back on the
main queue, asynchronously
and in this example I'm just
going to go ahead and loop
over those map items,
get their Placemarks
which have their coordinates
in it and I'm going
to remove any old Placemarks on
the map and add these new ones.
So, that's how you can put pins
on the map with Local Search.
So, that's Local Search.
Let's talk about a
closely related topic,
which is directions.
So, directions is a new API in
iOS 7 and it's on Mavericks.
It's a general purpose
route finding API support
in both driving and
walking directions.
We've got support for alternate
routes, so if there's more
than one good way to get there
and the server knows about it,
it can recommend them both.
And it also has support
for time estimates,
so by default this is based on
the current traffic conditions
but you can actually
set a departure date
or a desired arrival
time to the future
and we can use historical
traffic patterns
to estimate what the travel time
is going to be at that point.
So, that's the features of
directions and how do we use it.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, suppose we have this
method here and we want
to find directions
between two places.
It works a lot like search.
We make a request object, we
initialize it with a source
and destination and
those are MKMapItems.
So, you can do a
local search for them
or make the up yourself.
You do that, create a
directions object and ask it
to calculate directions and
its going to come back to you
on the main thread
with either an error
in which case you probably
want to show like a UI alert
or NSAlert or do
something with that.
Otherwise, you're going
to show the response.
And so when I talk about showing
the responsibility there's a lot
of things you can do about it.
There's a lot of data
in this response.
And let's just go through really
quickly what is available.
So, we echo back to you
the source and destination.
So an example of this is like
if you get directions to a place
and you know you put
it at this coordinate
but the direction server thinks
oh, you really should arrive
at this point because it's
going to be easier to turn
into the driveway or whatever.
It may move that site, so
you want to look at those.
It's going to come back
with a list of routes
so each route is going
to have a name to it.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, this is sort of the
name of the way that you go
like US 101 South, if
you're getting directions
from here down to Cupertino.
It's going to give
you a distance.
It's going to giving
you any advisory notice
like if it requires tolls
and you can display
that to the user.
There's going to be an expected
travel time and there's going
to be the geometry
as a polyline.
And also there's going
to be a list of turn
by turn instructions,
so these are the steps.
And so these are going
to be the instructions,
so for instance take exit 11
on the De Anza Boulevard would
be one your last steps driving
down to Apple Headquarters.
There may be a notice on some
of the steps, so you may want
to present that in
some special UI.
You'll get a distance and you'll
also get a transport type.
So, for instance, if you
got directions from here
to Coit Tower you can't drive
all the way to Coit Tower.
You can drive almost
there and then you got
to walk the rest of the way.
This step may have a
walking step at the end
if you got driving directions.
And then the other thing is
you can get the step geometry
as a polyline.
So, this is basically
the subsequence
of that overall geometry.
So, suppose we want to display
something like this on the map.
Here's the routes
from San Franciso
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
down to Cupertino,
three ways to do it.
And here's some code to do that.
So, we'll just loop over all
the routes and add an overlay
of those polylines for each
of the routes to the map.
The other thing you might
want to do is you might want
to show it in a table view.
So, for instance in California
there is always a way,
more than one way to get there.
You can take the 280,
you can take the 101,
you can take the 880.
You've got choices and
if you want to do this,
suppose we're the data
source for a table view.
And what we'll do is we'll have
this route, so we find the route
that we want to show and we'll
set the text of that cell
to the name of the route.
We have a new class in iOs 7,
also in Mavericks that's
a distance formatter.
This is an NSFormatter
subclass that allows you
to format distances according
to the user interface
language and locale.
So, in the United
States we'll use miles.
Elsewhere we'll use kilometers.
[ Applause ]
Cool. I'm glad you guys liked
that and we'll go ahead and use
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that distance formatter and
we'll use NS data formatter,
which I'm going to handwave
here and then we can show
that expected arrival
time in distance.
So, that's how we do that.
So, I'm going to do
a quick demo here
of adding walking
directions to an app.
I'm going to recycle
another demo.
This is one we showed last year
and what it did was it
showed Caltrain directions.
And it was really just kind of
a basic app and we just used it
to show routing apps in maps.
And I'm just going to
build and run this.
Get this guy going here.
It's really just you know a very
basic just kind of a sample app
and it gives Caltrain
directions between two points.
And the thing about Caltrian
is it doesn't go to Cupertino.
It goes to Sunnyvale.
And what we'd like to do is
sort of fill in the gaps.
Let's improve this app so we can
have walking directions to get
from you know how do we get
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to the train station
we're departing from
and from their arrival
transition how do we get
to our destination?
So, let's quit that and add
some code and some notes here.
So, what I'm going to do--
it's a sample application,
but it's kind of big.
And we don't need to
understand the whole thing
in order to modify it.
So, what we have here is the--
these are the properties on
this view controller here
and it has a route.
This route object is an internal
object to this application
and it represents
a Caltrain route.
So, this is what it has.
What I want to add alongside
of this is two MKRoutes
that we're going to get
from the Directions API.
So, we're going to have
the walking leg one.
This is how we get to our
departure train station
and walking leg two, which is--
this is how we get from
our arrival train station
to our final destination.
So, add properties for
that and what we're going
to do is just scroll down here.
And I see this method
here ClearRoute.
Obviously we just need
to add some stuff here.
So, if we clear that Caltrain
route let's also clear our
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
walking route.
That's good and once we've
gotten the route it goes ahead
and adds annotations for
the start and the stop
and it adds an overlay for
the Caltrain route's polyline.
And I'm going to add
those walking polylines.
I know we don't have them yet,
but hopefully we will get them
and when we do we're going
to want to show them.
Another thing I noted about
this is this is using this old
overlay, AddOverlay API.
It's just going to
add it AboveLabels.
Let's put them BelowLabels
while we're in here.
[ Silence ]
>> There we go, so a
bit of formatting there.
And let's go ahead and--
I know that we implement
ViewForOverlay in here.
This is old and busted, delete.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
New, RendererForOverlay.
So the only difference
here is we're going
to make polyline renderers
and we'll do a blue one
if the polyline that
we're being asked for,
the overlay we're being asked
for is for the Caltrain route.
Otherwise, it's one
of the walking routes.
Let's do a gray line.
So, we'll put that in there.
And then the last thing is the
thing we're all here to see.
There's this method
route from place in here.
So, this is an internal
object representing a place.
This is where we're
going to start leaving
from and where it goes to.
And what this application did is
it just said give me the closest
stop, the closest stop.
Well, how do we get there?
Don't know; this
app doesn't do that.
And then it just routes from
the start stop to the end stop.
Let's not do that.
Let's delete that and add this
code, just kind of a big block
of code and I'll walk you
through it really quickly.
So, we're going to make
a directions request
for the first leg.
We're going to set the transport
type to walking and we're going
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to set the source
and the destination
to be the start place,
so this is
where we're actually
departing from where we are now
and then we're going to
set it to the train station
that we want to leave from.
So, we'll create a
directions object for that.
Ask it to calculate directions
and it's going to come back
to us on the main queue
and either we're going
to be having an error in
which case we're going to have
to display an alert and we're
all going to be very sad
or we'll get back a walking leg.
So, this is-- we didn't
ask for alternate routes,
so there's going to be just one.
So, we'll get that first route
and we'll stash in
that property.
So, we'll do the same thing for
leg two and hopefully we succeed
and we end up stashing it there
and then finally we can get
the Caltrain directions now
that we've got the walking
directions that we need.
And the thing I'll say
about this is for simplicity
up here I've done
these serially.
You could run them in
parallel if you want.
There's no reason that
you can't do that.
I just did it this
way to be simple.
So, let's just build and run.
[ Silence ]
Directions.
And the other thing I would say
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
about this is I actually
cheated a little bit and I went
and I updated this
sample I had this time
to use LocalSearch instead
of using the Geocoder,
which it originally is.
So, we can actually go from
Mascone West now and let's go
to a place in Palo
Alto that I know
about called Antonio's Nuthouse.
Get directions, and
now if we zoom
in on the map we can see
we've got walking directions
from Mascone West here,
walk down 4th Street;
it's not a long walk, get on
the Caltrain at 4th and King,
zoom out, go down and
we'll get off in Palo Alto
at the [inaudible] Station
and it's just a short block
and a half walk to the
Nuthouse, which is right here.
So, that's how you can
add walking directions
to an existing routing app.
And this is really just kind of
scratching the surface of it.
[ Applause ]
Thank you.
There's obviously a lot
more you could do with it.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This just sort of
scratches the surface
but I hope you get
the idea there.
Let's go back to the slides.
So, we saw how to use
the Directions API
to augment an existing
routing app.
So, I hope that if you have a
routing app right now you have
something on there
stored and you say oh,
I wish I had walking directions.
I wish I could add this.
Please go ahead and do that
and then the other
thing we saw is how
to show those MKRoutes
on MKMapView.
So, that's that.
So, now I want to talk about
the fact that Directions
and Search are server-based.
So, they require a network
connection to operate.
And the other thing I'll say
about them is don't cache
the results for too long.
If you get driving directions
and you hold onto them
for a week, you know
you store them on disk,
you pull those back up,
things may have changed.
The traffic conditions
may have changed.
There may be a road closure
or something like that.
So, you want to rerequest
those things
to get more up to date data.
And the same thing goes
for Search as well.
And the other thing
I want to talk
about is the Usage
Limits on this API.
So, I'm happy to announce
that there's no application
or developer identifier
wide usage limits.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, if you have a app that has
a lot of users and you want
to do a lot of requests,
that's fine.
It'll work.
[ Applause ]
And the throttling that we do
have is really just a first line
of defense against buggy apps.
So, if you put directions
requests
or local search requests in an
infinite loop, you've got a bug,
eventually you're
going to get throttled.
But if you do something
reasonable, you say oh,
I'm going to just do directions
in response to user input
and you know you can
do a few of those
because we showed
them that example.
Like we did two directions
request in response
to one user input, that's fine.
But, you know if you're doing
10,000 every time the user taps
on the screen, then you're
going to get throttled.
But, just keep it
reasonable and you'll be fine.
So, that's everything.
Let's go into our conclusion.
So, what did we learn?
There's many new features.
In fact, we couldn't even
have covered them all
in this session.
We have a session coming up.
The first of which
was Map Kit OS X,
which is I think my
favorite feature.
I'm really excited to see what
you guys come up with on OS X.
There's the updates to iOS 7 UI.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, there's a new UI in iOS 7
and that changes a few
things in MKMapView.
We've got 3D maps and
spanning the 180th meridian.
We've got new Overlays
Functionality
so we've got polylines,
polygons,
other overlays underneath
your labels.
We've got the geodesic
polylines.
We've got MKTileOverlay.
We've got the ability to replace
Apple's Map Data with your own
and we've got Performance
Improvement for Overlays.
We've got the Search API
and the Directions API.
So, what I'd like to ask you
to do is try these things out.
Try them soon.
Like try them this week.
Try them next week.
I want it to work for you,
but if it doesn't please go
to bugreport.apple.com and file
a bug so that we can fix it.
For more information you can
email our Evangelist who's
Paul Marcos.
That's his email up there.
We've got some Documentation.
I know that's a long URL but if
you on our website and search
for MKMapUIDeveloper.apple.com
you'll find it.
There's also the Location
Awareness Programming Guide,
which has info on
both Core Location
and Map Kit, which is good.
And there's the Developer Forum
which I try to read occasionally
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and so I may see you in there.
And the next thing to say is
we've got a session at 2:00.
You should go to the session.
It's the second half of this.
There's a whole bunch
more content on 3D Maps.
We also got Static Map
Snapshots, which we're going
to cover in there
and you should attend
that session this afternoon.
So, that's everything.
Thank you all very much.
[ Applause ]