Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2009-118
$eventId
ID of event: wwdc2009
$eventContentId
ID of session without event part: 118
$eventShortId
Shortened ID of event: wwdc09
$year
Year of session: 2009
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2009] [Session 118] Embedding M...

WWDC09 • Session 118

Embedding Maps in iPhone Applications

iPhone • 51:49

Using the new Map Kit framework that works with the Google Mobile Maps Service, you can now embed maps within your applications. Find out how to effectively display a map, create custom annotations that highlight places of interest, and turn location coordinates into readable addresses.

Speakers: Chris Blumenberg, James Howard, Kimon Tsinteris, Seejo Pylappan

Unlisted on Apple Developer site

Downloads from Apple

SD Video (144 MB)

Transcript

This transcript has potential transcription errors. We are working on an improved version.

Welcome to session 118, Embedding Maps in iPhone Applications. I'm Chris Blumenberg I manage the iPhone maps team. So after the iPhone SDK came out a year ago, we quickly realized that there are so many map apps. There's an app that lets you find your friends that uses the map, there's an application that let's you make reservations at restaurants that also uses a map, there's an app that lets you speed without getting caught by the cops which also uses a map.

[Laughter] And these are just a few of the many applications out there, already out there that use a map. And that's when we realized we really need to come out with an SDK for mapping. An SDK for mapping would allow developers like yourselves to embed a map in your application and not have to write it yourself. And for users, it would allow the same seamless mapping experience across multiple applications.

So that's when we came up with MapKit. So MapKit is a new framework in iPhone OS 3.0 that essentially allows you to embed a map in your application. So what is MapKit? As I said, it's a new framework in iPhone OS 3.0. You can embed a map in your app using MapKit.

We use Google for all the map data, that is the map tiles as well as the services related to MapKit in the map. It responds to all the sort of panning and zooming gestures that you're accustomed to on the iPhone platform and in the maps application. You can also annotate the map in any way you want.

You can have custom views or built-in views, and I'll go into that shortly. A map can also provide reverse geocoding. So if you want to turn a coordinate, that is a latitude and longitude into an address that is something that's human readable, an address like you know, 800 Howard Street, you can do that with reverse geocoding that's also provided in MapKit. So once you get one of these addresses, you can then turn that into an Address Book contact if you wish to have that feature in your application. So what you'll learn today.

We'll teach you how to embed a map in your app using MKMapView. MKMapView is the UIView class for-- that contains the map. Once you have one of these MKMapViews, we'll show you how to control the map position and other properties of the map. We'll show you how to add views to the maps so you can add your custom views or built-in views and we'll go into that shortly.

And we'll also show you how to show the user's location on the map so the user can find out where they are in the world and in relation to you, you know, your annotations and all that. And then lastly, we're going to go into reverse geocoding, how to turn a coordinate into an address.

The class to do that is called MKReverseGeocoder. So this is a MapView on the right here. It's a UIView subclass. You can just call initWithFrame to create one of these things. You can call it-- you can drag it from interface builder into your application, it's really easy, it works right out of the box. It will start loading tiles automatically.

The user can start panning around and load tiles in those new locations. The users can zoom in and pinch and do that and we handle all of those things automatically. It's really easy to create one of these MKMapViews. We spent a lot of time working on performance. MapKit and MKMapView is written from scratch for iPhone and iPod Touch.

The data is cached, that is the map tiles are cached in memory and on disk. This is another thing you don't have to worry about. So if the user has been to a location before, chances are we'll be able to load tiles in those locations again if the user goes back to that location. MKMapView also handles memory notifications.

So if the system is running low on memory, we'll listen to those memory notifications and free up memory in the cache as need be. MKMapView also handles the connectivity changes. So if you have a device that's going from 3G to EDGE or EDGE to 3G or Wi-Fi or, you know, all those permutations, we'll go and reload tiles if necessary. This is all automatic behavior.

As I mentioned before, the map data is hosted by Google. Essentially a network is required to use MKMapView. You might get lucky or a user might get lucky if, you know, they load an MKMapView and the tiles are cached and we can retrieve those from cache while you're offline. But you have to remember that MKMapView is something that can be used sort of fluidly and the user can pan it to any part of the world and essentially a network is required.

There is also a delegate on MKMapView. Just set your delegate by setting the delegate property in MKMapView, and it's told when the map is loading for any reason. If you implement these loading methods, you might want to show a spinning progress indicator in the status bar. So as I mentioned, it responds to all the panning gestures that you'd expect on the iPhone. Pinch to zoom in, you know, reverse pinch to zoom out, double-tap zooms in for the next zoom level, two-finger-tap zooms out to the previous zoom level.

People aren't actually-- some people don't actually know about that gesture but two-finger-tap, just one tap will zoom out to the previous zoom level. So now I want to get into the API just a little bit. MKMapView supports different map types. First of all there is regular as you see to the right there, there's satellite, there's hybrid. Hybrid is a mixture of regular and satellite. And to change these map types is as easy as just changing a single property, very straightforward.

So once you have one of these MKMapViews in your application, the first thing you may want to do is start changing the region property. The region property controls the position and the zoom level of the map, that is where the map is currently focused. Regions are just like rectangles.

As you see highlighted in red there, that's-- what we're showing there is the current region. It's just like a rectangle in that it has a size and an origin associated with it. Regions are also animatable. So if you want to zoom from one part of the world to another part of the world, we have a very easy API that allows you to do that. So let's delve into this a little deeper.

This is a region, it's called an MKCoordinateRegion, it's a struct, consists of 2 things, a center and a span. The center is one of the CLLocationCoordinate2D structs which just consists of a latitude and longitude. This is the center of the region. In this particular case, the center is somewhere in San Francisco, and then the span, which is essentially the width and the height of the region.

The span consists of a latitudeDelta and a longitudeDelta. These are the values as the latitude and longitude are-- delta or changed throughout the region. And the latitudeDelta is the height and the longitudeDelta is the width of your region. So here's an example of zooming into street level. The current region here is showing, you know, San Francisco, the peninsula here. The first thing you want to do is to zoom to street level perhaps, is create a new region struct.

You'll set the latitude and longitude to something like you know, in this case somewhere in San Francisco. And I'm setting the span here to something rather small, meaning I wanted to zoom in to a sort of small portion of the world. And then it's easy as just setting that property on MapView. This is the region that we want to go to and this is the region that we end up going to once you set that region property, really straightforward.

And here is another example. In this case, I want to zoom out back to the Bay Area, create another region, set the latitude and longitude to somewhere in the Bay Area, and I'm setting the span here but I'm setting the span to something bigger, meaning I want to focus on a larger portion of the world. In that case, I animated the region change by calling setRegion animated. Did everybody see that animation, OK, thank you.

[ Laughter ]

[ Applause ]

So we actually-- we actually, you know, spent a lot of time working on those animations.

We actually cross fade tiles when necessary, make it as fluid as possible. So an important thing to note about regions is that the map uses zoom levels. We have different sets of map tiles at each zoom level. When you set your region, we go to the zoom level that best fits the region that you've set. So I'm going to walk you through what we do in MapKit when you set a region.

So here again is my map and I want to set that region to downtown San Francisco. First thing we'll do is recenter the map to the center coordinate of your region, pretty straightforward, and then we start stepping through the zoom levels till we find the best zoom level that fits. So this next one seems to fit pretty well, maybe we can do better.

That one looks pretty good, maybe we can do even better. And that region does not fit. As you can tell, the region that you've set intersects the visible region and that's just not going to work. So what we end up doing is going to this region when you set a region.

The result of this is that the resulting span of your region will not equal the span that was set. So in this particular case, we have set this region in that red rectangle there, but this is the region that we end up actually going to when the region is actually set.

And as you can see, the span values aren't quite equal in this particular case, so it's something to keep track of. The last thing I want to do concerning MKMapView and setting the position of your MKMapView is the centerCoordinate property. The centerCoordinate property allows you to change the position of the map without messing around with the zoom levels.

So for example if you want to just scroll from like maybe one little restaurant to another little restaurant, just a small little change, you'll probably just want to use the centerCoordinate property. And the centerCoordinate property is also animatable. So if you want to sort of animate that scroll, you can do that with a really easy API. So now I like to invite Kimon up on stage to give you a demo of how easy it is to create an MKMapView.

Kimon.

Thanks Chris.

[ Applause ]

So, I like to show you how simple it is to embed our mapping technologies into an iPhone OS 3.0 application. So for that, we're just going to go ahead and start with a brand new Xcode project, we're going to make it view controller based and we're going to call it world map for the purposes of this demo.

Now the first step, after of course you resize your windows, is to always link against the MapKit framework, there. The second step can be as simple as just editing your view controller's NIB and just dragging and dropping a MapView instance out of the library and into your interface builder's file.

Let's build and run to see what that looks like, OK. World map, you can double tap to zoom in, you can pan around, you can pinch to zoom out, pinch to zoom in, pretty much all the gestures that you've kind of grown to love and expect out of a map-enabled application on the phone.

Now, wouldn't it be nice if our world map supported say searching for locations, you know, you're wondering where Brazil was or the Galapagos. That process of converting an address to a coordinate, one that you can use with a MapKit API is called geocoding. So, for the purpose of this demo, I've gone ahead and just created a little geocoder class for us.

There is nothing special about it. There's a myriad of free services out there just, you know, pick the one of your choosing...

[ Pause ]

The interesting part is really going to be what happens on geocoder completion. I'm updating our view controller here a little. Basically the geocoder delegate just defines a, you know, geocoder didFind region and all we have to do is just set the mapView's region with the setRegion animated selector. On failure, you know, we handle that as well. Hopefully we won't be exercising that code path today. Now as I mentioned, we want the user to be able to search. Excuse me.

OK. So, let's go ahead and add a search bar. Let's resize our MapView and let's just hook up some outlets. So basically our view controller has a MapView outlet and a search bar outlet. Let's also make our search bar's delegate our view controller. Now let's build and run. OK, so we have our search bar.

We can type in a zip code, we can type in a city, we can also type in a continent. And as you can see, MKMapView automatically just adjust both the center coordinate and the zoom level to accommodate that geographic bounds. So, wouldn't it be nice if our world map application can go portrait, excuse me, landscape. So what's that going to take? Basically, in our view controller class, 'cause they should auto rotate to interface orientation selector, and every UIViewController subclass can implement this. Let's just try returning YES here.

They'll then run that. So I believe we were down under last. Let's try that again. There you go. So it's pretty much that simple [applause] to create a world map application fully functioning with a very few lines of code. Thank you, back to you, Chris.

Thank you, Kimon. So that's how easy it is to create one of these MKMapViews.

This actually takes no line of code whatsoever. So, once you have one of these MKMapViews, the next thing you may want to do is decorate the map with your own views, and that's what we call annotations. And those are some annotations to the right there. So annotations essentially allow you to annotate the map with views.

These can be custom views, if you want some sort of custom behavior associated with your annotations, or these can be built-in views like the red pins that we provide in the API. Annotations correspond to coordinates on the map. They're essentially stuck in the coordinate that you specify for your annotation. If the user pans around, that annotation will remain in that position on the coordinate map, it will pan off. User zooms in or zooms out.

They remain stuck in those coordinates. We ask that you actually use this API. Please use annotations. It's not a good idea to add subviews to MKMapView directly. Unexpected things might happen, your views might get scaled or they might not follow the map. Also, the view hierarchy in MKMapView is private. We reserve the right to change the structure in there. If you make any assumptions about it, in the future you might break.

So we can change it at any time, so please don't go digging around. So with annotations, your application provides a model and a view for each annotation. A model, the model object could be something like your data object. Let's say you have a restaurant application, your model object would be an object that describes the restaurant like the address, the name of the restaurant, the coordinate for your restaurant. The view is the thing that actually gets placed on the map for your annotation model object.

So those are the views for example off to the right, those red pins. MKMapView determines when these views should be created. So we have another delegate method on MKMapView that gets called whenever the map determines that it needs to create one of these annotation views. So that views, the argument is pretty important and we'll go into that shortly.

For large data sets, let's say you have a database of all Starbucks in the United States, all 30,000. It's not a good idea to add them all to MKMapView in one shot like that. You know, this is a limited device with a limited amount of memory. If you were to do that, your app will probably exit.

So the right thing to do is to listen to region changes. We have yet another set of delegate methods for when the region changes and what you want to do when the region change is add and remove annotations as appropriate. Generally staying around 100 annotations max is a good amount for now. So this is an annotation model object. Essentially, your model object conforms to the MKAnnotation protocol.

When you have these model objects, you add and remove them to MKMapView when you want to add and remove annotations. On the protocol there's only one required property, and that's the coordinate. Every annotation must have a coordinate, otherwise you know, it wouldn't really work for the map. The other API here is MKAnnotationView.

This is the view that actually gets placed on the map like the red pin you see here. MKAnnotationView can be subclassed if you want some sort of custom behavior. We also have a method on MKAnnotationView to change the image. So if you want to create an MKAnnotationView from scratch and just change the image, provide some sort of custom artwork, it's very easy to do that We provide built-in views like this red pin as you see here, and I'll go into that shortly.

Like UITableViewCell, annotation views are reusable. If your application is adding and removing annotation views very frequently, let's say if you have a large dataset or for some other reason, you're going to want them to be reusable and we'll go into that shortly as well. As I mentioned before, MKMapView determines when these things get created.

You shouldn't have to create them you know, outside of that. Well there's a delegate method for when these views should get created and returned back to MKMapView. When we call this delegate method, we give you the corresponding model object that you provided. So essentially, this delegate method creates an MKAnnotationView given your model object.

If you don't provide a view, say for example if you don't implement the delegate method or if you return nil, we'll create one of these red pins for you automatically. So, if you don't want to get into the view game, if you don't want any special behavior or appearance, you don't have to implement any delegate methods whatsoever.

Lastly, MKMapView positions your views. We determine where in the world your annotation views will go. We have some hooks in there to slightly tweak the locations of your annotation views and I'll go into that in a bit. So now I'm going to go through the flow of adding an annotation to MKMapView, there's a few steps involved. The first thing that happens, step 1, is that your app creates an annotation and adds it to MKMapView. Step 2, the MapView asks the delegate to create an annotation view.

We determine that an annotation view needs to be created for your annotation and we'll call mapView:viewForAnnotation. In your implementation of mapView:viewForAnnotation, you will go and create an annotation view and return back to MKMapView. Step 4, the MapView positions the annotation view. We plop it on the map. And as you can see there, it's great, meaning it's been positioned on the map but it's not yet visible to the user. We still have a few steps to go here.

Step 5, the MapView then tells the delegate about all of the recently added annotation views.

So all these pins there in gray have recently been added but they're not yet visible to the user. So the delegate method for telling you about all the recent added annotation views is mapView:didAddAnnotationViews. And step 6, this is the last step and this is an optional step.

You can decide to animate your recently added annotation views. In this particular case or in this particular implementation of didAddAnnotationViews, our delegate wants to make them drop from the sky. And that's how you do that. Now dropping from the sky is just one example of animating your added annotation views.

You can have thunderbolts or Godzilla burning holes in the map, whatever you want to do, there's other animations you can do. It's pretty open ended. So this is an example implementation of viewForAnnotation. The first thing it does is it checks if there's a reusable annotation view. The method for that is dequeueReusableAnnotationViewWithIdentifier.

If one exists, just return it right back to the MKMapView and you're done. When it doesn't exist, you want to go and create your annotation view. In this particular implementation, we're creating an annotation view and setting a custom logo on it, and then we return it back. So that's pretty much it for creating an annotation view.

The end result of doing that would be something like this. So, you have your annotation views, they're all in the map, everything looks great. Now here's an example of animating those logos, and you'll want to do that inside of didAddAnnotationViews, that delegate method The first thing you might want to do is grab the annotationVisibleRect. That's another method or that's another property rather on MKMapView. The annotationVisibleRect is where your annotations are in the visible area currently. The next thing you might want to do is iterate through the views.

Remember, they are already in their ultimate position. They're in gray, right, so the end frame of your animation is the current frame that's set by the time this method is called. The start frame in this particular case, I want to make these logos fall from the sky. The start frame is just off screen slightly above the visibleRect, and that's just some lame math for doing that.

And then, lastly there's my animation block. Here, I am taking the view from the top of the-- from off screen to dropping it to its ultimate location. And the end result of all this would be something like that. So it's pretty simple, that's what you do for animating your recently added annotation views.

Again this is pretty open ended, you can do pretty much any animation you want there. So as I said before, you might want to tweak the positioning of your annotation view. By default, what we do is we take your annotation view and get it centered and position that over the coordinate of your annotation.

So for this WWDC sign here, the center of my artwork there is somewhere in the middle of the sign. What I'd really like is for the stake for where the sign is in the ground, I want that to be positioned at the entrance of Moscone West. So this is the default behavior here. But I want to slightly tweak it in pixels relative to my annotation view.

I can slightly tweak it using the centerOffset property. So here is an example of doing that. Here I'm just changing the offset, the centerOffset, moving it to the right slightly and then moving it up a bit such that my WWDC billboard is staked to the ground at Moscone West. So if you look at the map there, you'll see the end result of changing the centerOffset property.

And that's where I want it to be, and as you can see that looks a lot better. So once you have these annotation views positioned on the map, the next thing you might want to do is play around with selection. Annotations are user selectable, that users can tap on them and a little callout will appear.

They're also selected programatically so we have methods on MKMapView just to select and deselect annotation views automatically for the user. Whenever an annotation view becomes selected, whenever they're tapped on, the selected property on MKAnnnotationView is set to YES. If you want some sort of custom selection, what you'll want to do is override set selected on MKAnnotationView and show your custom selection UI.

If you want the built-in selection UI, what we call the callout, displaying Moscone West there, just set the canShow property to YES on MKAnnotationView. And whenever an annotation view is tapped, this default selection UI will be shown. To show the selection UI, to show the callout as we call it, the title property on your annotation model object must be implemented. We can't show a callout without the title.

Also, if your annotation model object has a subtitle, we'll show it sort of optionally beneath the title as you see there. So we see Moscone West with the address 800 Howard Street slightly below it, that's the subtitle. Also on the callout, we support accessory views, we support a left accessory view and a right accessory view. These again are properties on MKAnnotationView. In this particular case, I'm setting the callout, the left accessory to an info button with an I and the right accessory view to a disclosure button, pretty straightforward.

If these accessory views happen to be UI controls, it's pretty easy. We'll automatically call a delegate method. It's called mapView annotationView, calloutAccessoryControlTapped whenever these accessories are tapped. So there's no need to call addTarget:action:forControlEvents. There's no need to hook this up, we do this all pretty much automatically for you with this delegate method.

The last thing I wanted to cover concerning annotations is one of the built-in annotation views that we provide. This is MKPinAnnotationView. These are those red pins you see off to the right there. We support red, green, and purple pins. Generally the guidelines are red means generic You can-- these are the HI guidelines and these are pretty general, but red means generic. You can pretty much do whatever you want with the red pin.

Green represents a starting point, so if you want to have sort of a route or start and end point, you want to use green to represent the starting point. Purple is user defined, so you should leave it up the user to define where a purple pin gets located. Lastly, the other thing on MKPinAnnotationView is animatesDrop property. It's a built in animation that we provide.

If you set this to YES, whenever an MKPinAnnotationView is used on the map, we'll automatically drop them from the sky and bounce and the shadows will meet up and all that. So if you look to the right at the map there, you'll see an example of that happening.

That's all built-in into MapView. So now I'd like to invite James up on stage to give you a demo of annotations.

I'm going to show you how to use annotations to show what the weather is like around the country. So to get started, I've put together just a bare amount of code that's necessary to get a map on screen, so basically picking up where the first part of Kimon's demo left off. So I'm just showing a map, setting it to the United States.

And if we build and run this, we get something like that. So, let's flip back over to Xcode here. For my annotation, so this is my weather model object, I have a few properties defined in this. I've got temperature, weather type, so that's like is it cloudy, is it stormy, is it sunny, and then of course coordinate which is a required property on MKAnnotation. I also go ahead and implement the optional method here, title, so that will show in a little callout there.

And for the weather, I just show the temperature in Fahrenheit. I also have a weather manager here. This talks to Yahoo's weather RSS service, and it just gets the weather for a region. And so if we flip back over to the view controller here, as soon as the view loads, I'm going to go and ask my weather manager to load the weather and the region that I'm showing.

And it's going to call me back down here.

[ Pause ]

Hopefully it doesn't get an error. And I'm just going to use addAnnotation so you can just add a list of annotations, so this is going to be the weather info objects that you saw earlier, add those to the map. And without implementing any other MKMapView delegate methods, this is just going to put red pins on the map.

So now if we build and run, we get these red pins on the map. So we can see like up in New York the weather is 62, down in Texas it's 92 degrees, in Alaska 47, Seattle where I'm from it's 65. So this is good, but these are just the default red pins that you get. We'd like to spice things up a little bit and get something that says weather a little more than a red pin.

So in order to do that, I've already defined an annotation view so I'm just subclassing MKAnnotationView here. And because MKAnnotationView is a subclass of UIView, you can just do drawRect and draw whatever you want in there. In my case I'm going to draw like a little blue badge and then I'm going to draw an icon for the weather and I'm also going to draw the temperature in the bottom of this.

A coupl.e of things to know, if you do use drawRect to draw your annotations, make sure you set the bounds.

I'm saying this is, you know, 40 by 50.sty@l This way, the map will know how to center your annotation right over the coordinate that's set. I'm also setting enable to NO. I'm going to have all the information I need just in my view, so there's no need to show a callout.

So, if we flip back over to the view controller here, we can implement the viewForAnnotation delegate method. And as Chris showed early in his slide, what we want to do is-- clean this up a little bit. You can dequeue a reusable annotation. So if, you know, you've added one and you removed one, it's going to-- we're going to keep them around for a little bit, that way you're not constantly creating a ton of views.

If we are unable to dequeue one, we're going to create one and return it. There's no need to set the annotation if you did dequeue it. The mapView will do that for you. But otherwise, this works a lot like if you're familiar with UITableView, the delegate method on that to get a cell.

So with this in place, we build and run.

[ Pause ]

Now we get these nice little blue badges. Looks like it's hazy over New York, cloudy in Seattle, in Southern California it's pretty much sunny. So this is nice. What happens if we drill into the Bay Area? Nothing. What we want to do is we want to watch for these region changes.

So every time the map moves or zooms, we get a callback from MKMapView, and we could take advantage of that to add more annotations to the map, so let's do that. So on this region did change. We will just go back and ask the weather manager for more weather. It's going to load more weather and it's going to call back here and we're going to add more annotations to the map.

So, if we build and run with this-- What? It's--

[ Pause ]

Alright, so now we'll drill into the Bay Area and wait for it, more weather. We can scroll around, load more weather, go back, load more weather, zoom out, load more weather [laughter] zoom out again, load more weather. Eventually we run into this situation where we have like this big mess of stuff on screen, there's way too much going on and eventually, you know, we'll be adding so many annotations to the map that we probably get a memory notification and be forced to quit.

So, what we need to do is we're going to start culling some annotations. So to do that, I've already defined a category on the view controller here which culls annotations and add annotations. In my case, what I'm doing is the server is always sort of preferring to return the biggest cities. So, as you saw like I had like New York, I had Seattle, I had L.A., I had probably like-- I don't know, whatever the capital of Texas is. [Laughter] No offense intended or implied towards any Texans, I just honestly don't know.

But anyways--

[ Laughter ]

Austin.

Austin. So, initially I'm adding the biggest cities to the map. Then what I'm doing is as you zoom in, I'm adding like more and more local weather, so smaller cities. As we move around, we want to move things that are off screen, we want to remove those from the map, bring in new things. But we never want to have any two things overlap.

So I'm just doing something kind of lame here. I'm just doing like the N squared thing. I add up. As I'm adding things to the map I say, oh, this area is blocked off if anything new comes along. Well, it must be a smaller place so I'm not going to replace it. But if there's room, I'll put it on there.

So depending on what you're doing to your application, you may want to do different things, you may want to like cluster things, you may want to have other priorities for what stays on the map and what gets removed. But if you're in a situation where you have a lot of annotations that you could potentially display, you need to think about this problem then and decides what's best for you.

So, if we flip back over to view controller, we can make use of this. So as soon as we change the region, we can call this and this is going to move-- everything that's off screen is going to remove it. So, we can add that back to our queue and save the-- and get rid of the views. And also, rather than just blindly adding more annotations-- oops, blindly adding more annotations when we get this callback, let's cull and add.

[ Pause ]

It should be, you know, here. So now if we build and run--

[ Pause ]

Now as we drill into the Bay Area, reload weather but not overlapping. If we like scroll over, we'll load some new weather in here. Scroll back, the stuff that was off screen has been removed. You zoom out, things are moved to make more space and new things load in.

So, there's a little over 30,000 zip codes in the United States, that's potentially how many annotations there could be. So, this demonstrates a way that you can choose between those and get good performance and something then looks good on your map. So, that's annotations and MapViews.

Thank you, Chris.

[ Applause ]

Thanks, James. I never thought weather could be that exciting So, we've shown you how to create an MKMapView, annotate it anyway you want. The next thing you may want to do is show the user's location on the map. And that's our sort of built-in UI for showing the user's location. You may be accustomed to seeing that in the maps application.

So, how do you do that? Well first of all, MKMap, MKMapView uses CoreLocation. CoreLocation uses a combination of cell, Wi-Fi and GPS to get the users, the best representation of the user's current location. To simply just show the user's location on the map, set the showsUserLocation property to YES, and once the user's location becomes available from CoreLocation, we'll show it on the map. It's that simple. The user location is also an annotation. There's a model object, there's a way to get at the annotation for the user location. We'll go into that shortly.

And for the view, we provide a built-in view as you see there. So, that annotation for the user's location is called MKUserLocation. As I said before, MKMapView provides the view for this annotation model object by default. As a delegate of MKMapView, you can decide to show the built-in view, the one that you see there, or you can show a custom view if you wish to have a custom view for the user's location, you might want to do that. So, here's an example of using the built-in view. Again, we have mapView:viewForAnnotation.

To check if the annotation being passed in is the user's location, you just do a simple pointer comparison. You call the userLocation property on mapView. If they're equal, return nil. Return nil in this method always means use the built-in annotation view. But maybe you want your own sort of custom UI for the user's location, and here's an example of doing that. Again, we have that same pointer comparison, comparing the passed-in annotation with the userLocation annotation. But in this particular case, we're creating our own custom view for this userLocation and it's just simply creating one and returning it back, it's that simple.

So on MKUserLocation, there's a location object property, that's a CLLocation object. If you use CoreLocation, you'll know what a CLLocation is. It just basically represents the user's location, the coordinate for that user and the accuracy for that user. However, the location property on MKUserLocation is different than the one that you'll get from CLLocationManager. The location property on MKUserLocation is optimized for display on the map.

If you want to track the user's location, the one that is on the map, you can use key-value observing to do that. I'll go into that in a bit. CLLocationManager, as I mentioned, provides a different location object. The one that is represented by CLLocationManager represents the raw user location. So, here's an example of tracking the userLocation as you see it on the map.

And you want to use key-value observing to set up your server here. And then whenever that value changes, whenever it essentially moves on the map, your observer will get called. In this particular example, I'm just setting the centerCoordinate of my map to the userLocation. This is essentially a way to track or make them, make the map track the user automatically.

Also on MKUserLocation are the title and subtitle properties that I've mentioned before. However on MKuserLocation, they're mutable so you can actually override or change the title and the subtitle for this location. So whenever the userLocation is tapped, it will show the built-in callout UI as you see there. In this particular example, I've overridden it or rather set my name Chris as the title and the address or the subtitle in my current location being Moscone West.

This is just one example of using these properties. So, now I'd like to invite Kimon up on stage, he's already on stage, to give you a demo of userLocation in MKMapView.

Thanks, Chris. So userLocation, for this demo, I want us to build on our world map application.

What does it take to get the user's location in an MKMapView enabled application? Let's go over to interface builder, select our mapView and just check showsUserLocation.

Back in Xcode, if we build and run this-- I didn't save my name, you got to save your name. OK, the familiar user location UI that you know.

So basically under the hood we've kind of started up CoreLocation for you, we've added annotation to the map, we even provided the annotation view on your behalf. Wouldn't it be nice if we kind of provided the user an affordance for getting to their user location without having to pan and zoom? Let's see what that would look like.

So basically on our view controller, let's just define a new action, let's call it go to user location. The implementation of which is relatively straightforward. Basically, we examine our MapView, its user location annotation, do some error checking and then just compute a CoordinateRegion and showing a minimum metric horizontal and vertical distance that we zoom to. And then we just adjust the MapView's region with the typical setRegion animated selector.

Now back in interface builder, let's add an affordance for that action. Let's use a bar button item. Let's drag it over to our loop view controllers' NIB, and let's give it a spiffy image. I took up this action to a new Go to user location selector and let's build and run that, build and run that.

OK, we have our button, we can click on it, and there we are. We're at Moscone West, Presidio. So, what else can we add to the map that might be of interest? So personally I've always wondered what tweets might look like on a map. So for the purpose of this demo, I've gone ahead and kind of updated our view controller for some extra functionality.

It's going to have just one additional IB action toggle Twitter search and it's going to change the behavior of our search bar. It's either going to look for a location by the process of geocoding that I described earlier, or it's going to search on using Twitter's API for that twit for that particular text.

Now back in IB, let's add another bar button item. Let's give it another little icon, hook it up to our new toggle Twitter search action and build in on that. OK, so we have our previous functionality and those are the location. We can still browse to anywhere on the world, say Oahu.

And now we can actually see what people are saying, say about surf. Let me see, there's a few hits there, a few from the north shore. Northwest swell, glassy, 6 feet at 14 seconds, perfect surf. The surf is too good, left iPhone in pocket fail [inaudible]. [Laughter] We're coming out with a new one.

So it's OK, you can upgrade. Now you can browse it to reverse forever and it's pretty interesting, you know, matched up with geographic location information. But let's take it a little closer to home. So what are you guys saying about WWDC? [Laughter] OK, quite a few hits. I heard from a reliable source, it's Black Eyed Peas.

We can neither confirm nor deny that. [Inaudible] Chris, what are you doing Twittering an hour before our presentation? Beer and MapKit, today is a good day. Agreed. [Laughter] So, hopefully that has kind of given you an idea of how significant adding the user's location to the map is and maybe even giving you a few ideas for new and novel MK MapKit applications.

Thank you.

[ Applause ]

Thanks, Kimon. I'm definitely looking forward to having a beer after this presentation. So the last thing we want to cover today is geocoding. Geocoding essentially is a way to map from an address to a user-- address to a coordinate or vice versa. So I want to first describe forward geocoding. Forward geocoding is essentially a way to turn address into a coordinate, as Kimon sort of demoed earlier today.

So here is our address, this is the address for Moscone West. Forward geocoding essentially turns that address into our coordinate, a latitude and longitude Reverse geocoding, however, turns a coordinate into an address. So here we have our coordinate and this is the address we get back for it. So, MapKit only provides reverse geocoding, however, there are many forward geocoding services available online, simply a Google search away. There are a number of services out there, free and not free and it's pretty easy to use them. So let's go into reverse geocoding a little bit more.

The class is called MKReverseGeocoder. It performs reverse geocoding queries for you. It's actually very useful when combined with CoreLocation. CoreLocation gives you the user's current location in a coordinate but it doesn't give you an address for it. You combine that with MKReverseGeocoder, you can actually get the address for the user's current location. So it's pretty helpful. The queries for MKReverseGeocoder are done asynchronously.

We have another delegate on MKReverseGeocoder that will get called when your reverse geocoding either succeeds or fails. When it does succeed, you'll get a placemark. A placemark is an address and its associated coordinate. So as I mentioned, the delegate will get called when this either succeeds or fails. So here is an example of reverse geocoding the user's current location.

So here I'm just grabbing the coordinate off the userLocation object. I'm creating an MKReverseGeocoder. The only thing I need to give it is the coordinate, call initWithCoordinate and pass the coordinate to it. I'll set the delegate as myself and then call start, and that's all you need to do to kick off a reverse geocoder. And then if it succeeds, reverseGeocoder didFindPlacemark, didFindPlacemark will get called. In this particular example, I'm setting the subtitle to my user location callout to the locality of my placemark.

So what is all these placemark business? A placemark is an address essentially for coordinate. On MKPlacemark, it's essentially a model object. We provide all the address fields for the particular address like, you know, street, city, country and so on and so forth. Also on MKPlacemark is a dictionary representation method that you can call. Once you get one of these dictionaries, you can go and create an Address Book card if you want to do that.

It's also an annotation, so if you get a hold of an MKPlacemark, you can just simply add it to your mapView and it will just show up automatically, pretty simple. So here are all the properties, the address properties on MKPlacemark and a set of examples for them. I'm not going to read through all of these, but you get the idea. And these properties, essentially we consider them to be, you know, a work around the world.

They're sort of locale independent address properties. So now I'd like Seejo to give a demo of reverse geocoding. Seejo.

Thank you, Chris. What I want to show you is how easy it is to use reverse geocoding in MapKit based application and iPhone 3.0. To demo this, I have an application which takes a set of geotagged photos and put it on a mapView. Let me show how it works.

So clicking on load does the usual thing of animating through it, creating annotations. It asks for custom annotation view and that is what I'm doing. In my annotation view here I have a thumbnail of the actual photo. I have callouts which show me what the name of the photo is. I have implemented some code where the info bottom would actually give me the detail view.

You're probably familiar with it. That's the Golden Gate Bridge, if you don't know. There, to show you some more pictures before we go in detail, this is a very important building with a lot of graffiti on it. So this is great, but what I really want to do is to have an address for this.

For example, I came across this photo which shows me a very good pad thai and I want to go there for lunch today. So let's see what it takes to incorporate reverse geocoding in your MapKit applications. So going back to Xcode, I have a map photo which is my model object and that conforms to the annotation protocol which means that I have a coordinate, and that's the only thing you need.

So I'm going to add a method in here, which does the reverse geocoding call. And as Chris mentioned, it's very straightforward. All you do is you create an MKReverseGeocoder with the coordinate you're probably interested in, set the delegate yourself and call start. What that does is it will do its business. It will go outside and get the reverse geocoded address and gives you back in a placemark, and that's done with a delegate callback. So I have some delegate there.

And in my callback, I'm setting the placemark in my model object, then I post a notification which is basically telling my views which is showing this annotation that it can update itself to show the address and then I release the geocoder. Finally, what I add is I add the call to actually make the reverseGeocoder call in my init method, so as soon as the annotation is initialized, it does a reverse geocoding.

So let's build and run this app.

[ Pause ]

So now when I click on the photos, now I have an address associated with it. And like now I have-- all of those shows the details. One other thing which I have added is I have some code which would actually take the placemark information and turns that into an address.

So if I go into the detail for this view, it actually have an Address Book info there and I can click done, that would actually add it to the Address Book, so let's do it for that Thai place. I do it here, click done, now it's added to my address book to take a look at it. Let's go to my contacts, and I have those two places there. So that's reverse geocoding and MapKit. Back to you, Chris. Thank you.

[ Applause ]

Thanks Seejo. So, those are all the topics that we wanted to cover today. An important note is that MapKit works with the Google Mobile Maps Service. We encourage you to visit this URL to see the terms and conditions when using MapKit. This URL is also available on all the header files in the MapKit project. For more information, please contact Matt Drance. He's the Application Frameworks Evangelist. That's his email address there. For documentation, this is the URL that you might want to start up with to get documentation on MapKit, and there is the attendee site.