Services • iOS, OS X • 45:29
Learn about the latest improvements to Map Kit, including end-to-end directions and customized map view callouts. Find out how you can snapshot maps in various ways to optimize your content or use maps in new ways. And now, Map Kit is also available for OS X, so you explore how to enhance your Mac apps with maps.
Speakers: Alexandre Carlhian, James Howard
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
[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 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.
Here it is. We have an NP Map view and an NS Window 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 UI views 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 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. 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? 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. 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.
[ 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. 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. 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. 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 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 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 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. 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. 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.
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. 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. 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. 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 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 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. 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.
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 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 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 ]
[ 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 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. 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 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. 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 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 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. 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 NS alert 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. 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 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 NS formatter 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 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 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 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. 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 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 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. 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. 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. 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 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 ]