Update September 2016: Fully updated for Xcode 8 and Swift 3.
I usually like how MapKit framework comes with a great set of API to empower each map app. The first app I have built for iOS was empowered with MapKit (it was google maps at that time), so I feel it’s good to write a series of tutorials about it, ’cause I have a special respect to Apple for this framework.
This is the first tutorial in a series of tutorials about MapKit. In this post, you will learn how to easily search for addresses and POI and annotate them in the map, the process is also known as “forward geocoding”. Along the way, you will learn how to present the search bar over the navigation bar, the same way many iOS apps did (youtube app for instance), using the new iOS 8 “UIPresentationController” class.
Without further ado, let’s do this 🙂
Fire up Xcode, select “File\New\Project” from the menu, and as usual, select the ‘Single View Application’ template from the iOS tab, name your project ‘MapLocator’ and make sure ‘Swift’ is the selected language, and ‘Universal’ is the devices family to build for.
Let’s start by building the screen and setting some Auto Layout constraints so it gets adaptive on all screen sizes and orientations.
Select ‘Main.storyboard’ from the Project navigator view and choose the iPhone 6s model from the list of devices at the bottom menu of the canvas.
Click on the view controller from the canvas and select ‘Editor\Embed In\Navigation Controller’ from the menu, now the screen become the first controller in the navigation stack you just added. You may notice a navigation bar is added to the view controller, you will need this to place the search button and to experience the search bar presentation animation over the navigation bar.
Select the navigation bar from the Document Outline view and set its title to ‘Map Places’ from the ‘Attributes inspector’ view.
Now, let’s add a button to the navigation bar, this button will respond to clicks and hence fire a function to show the search bar. From the ‘Object library’, drag a ‘Bar Button Item’ and place it to the right of the navigation bar. Make sure it’s selected, then switch to the ‘Attributes inspector’ view, select the ‘System Item’ menu and choose ‘Search’ from the drop down list.
Add the Map
Let’s add the map to the view, drag a ‘Map Kit View’ object from the object library to the view, switch to the ‘Size inspector’ view and set the X to 0, Y to 64, Width to 375 and Height to 603.
The map needs to be placed correctly below the navigation bar to fill in the remaining screen space for all sizes and orientations. To ensure that, select the ‘Pin’ menu, make sure the ‘Constrain to margins’ checkbox is UNchecked, then activate the top, leading, bottom and trailing spacing constraints with 0 as a margin value. Finally, select the ‘Add Constraints’ button to apply the changes.
Cool, that’s it for the UI, now it’s time to hook up the objects to the code. The map view will be referenced as an outlet while the bar button item will be associated to an action method.
Switch to the ‘Assistant editor’ view and load the ‘ViewController.swift’ file in the split area.
1/ First, hold a ctrl click and drag a line from the search button to the code file (just below the class name), set the Connection to ‘Action’ and name it ‘showSearchBar’.
2/ Repeat the same work with the Map, hold a ctrl click, and drag a line from the map view object to the code, but this time, set the Connection to ‘Outlet’ and name it ‘mapView’.
Note: You may get an error of kind “Use of undeclared type ‘MKMapView'”, such error is thrown because the compiler couldn’t find the root class of the object you just added. You will fix this right away by importing the MapKit framework (where MKMapView class is declared), in the top of the class so that all MapKit classes and API can be imported and used in your code.
Add the following import line above the class name in “ViewController.swift”:
import MapKit
So far, here is how the ‘ViewController.swift’ file should look like:
import UIKit import MapKit class ViewController: UIViewController { @IBAction func showSearchBar(sender: AnyObject) { } @IBOutlet var mapView: MKMapView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
Run the app and check the map is displaying correctly on all screen sizes and orientations 🙂
Now place to the code, switch back to the Standard editor if it’s not already, and select ViewController.swift file from the Project navigator view.
Start by declaring some variables that you will need along the way performing map searches, etc. Implement the following code right after the class name:
var searchController:UISearchController! var annotation:MKAnnotation! var localSearchRequest:MKLocalSearchRequest! var localSearch:MKLocalSearch! var localSearchResponse:MKLocalSearchResponse! var error:NSError! var pointAnnotation:MKPointAnnotation! var pinAnnotationView:MKPinAnnotationView!
Let me explain what each variable is responsible for:
The ‘searchController’ variable will manage the presentation of the search bar and its animation, while the ‘annotation’ object will serve to reference any drawn annotation on the map and manage it. In order to perform a search of address or POI with MapKit, an ‘MKLocalSearchRequest’ object should be prepared and passed to the ‘MKLocalSearch’ object which will initiate the search process asynchronously and send back the search result stored in the ‘MKLocalSearchResponse’ object (NSError object is also delivered for any potential error stack). Finally the ‘MKPointAnnotation’ and ‘MKPinAnnotationView’ will work together to construct the pin and annotation which you will place at the location coordinates on the map 🙂
Next, copy the following code inside the ‘showSearchBar’ action method:
searchController = UISearchController(searchResultsController: nil) searchController.hidesNavigationBarDuringPresentation = false self.searchController.searchBar.delegate = self present(searchController, animated: true, completion: nil)
The code above will instantiate the search controller object and present it above the navigation bar with an animation, the ‘hidesNavigationBarDuringPresentation’ property should be better set to false, but you can still hide the navigation bar if you want by setting it to true (although that will result in a bad transition in our case).
You also set the view controller as the delegate of the search bar, you will implement one more function related to the search bar delegate protocol in order to respond to the search button click event on the keyboard and fire the search process. But before, let’s make the class adopt to the search bar protocol to respond to such events. Go ahead and change the class declaration to the following:
class ViewController: UIViewController, UISearchBarDelegate {
Cool, finally, let’s implement the last snippet of code. Once you click the keyboard search button, the app will perform all the search work we talked about previously. Place the following code before the closing bracket of the class:
func searchBarSearchButtonClicked(_ searchBar: UISearchBar){ //1 searchBar.resignFirstResponder() dismiss(animated: true, completion: nil) if self.mapView.annotations.count != 0{ annotation = self.mapView.annotations[0] self.mapView.removeAnnotation(annotation) } //2 localSearchRequest = MKLocalSearchRequest() localSearchRequest.naturalLanguageQuery = searchBar.text localSearch = MKLocalSearch(request: localSearchRequest) localSearch.start { (localSearchResponse, error) -> Void in if localSearchResponse == nil{ let alertController = UIAlertController(title: nil, message: "Place Not Found", preferredStyle: UIAlertControllerStyle.alert) alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default, handler: nil)) self.present(alertController, animated: true, completion: nil) return } //3 self.pointAnnotation = MKPointAnnotation() self.pointAnnotation.title = searchBar.text self.pointAnnotation.coordinate = CLLocationCoordinate2D(latitude: localSearchResponse!.boundingRegion.center.latitude, longitude: localSearchResponse!.boundingRegion.center.longitude) self.pinAnnotationView = MKPinAnnotationView(annotation: self.pointAnnotation, reuseIdentifier: nil) self.mapView.centerCoordinate = self.pointAnnotation.coordinate self.mapView.addAnnotation(self.pinAnnotationView.annotation!) } }
The code above is the last piece in the puzzle, let’s explain its main parts commented above:
//1: Once you click the keyboard search button, the app will dismiss the presented search controller you were presenting over the navigation bar. Then, the map view will look for any previously drawn annotation on the map and remove it since it will no longer be needed.
//2: After that, the search process will be initiated asynchronously by transforming the search bar text into a natural language query, the ‘naturalLanguageQuery’ is very important in order to look up for -even an incomplete- addresses and POI (point of interests) like restaurants, Coffeehouse, etc.
//3 Mainly, If the search API returns a valid coordinates for the place, then the app will instantiate a 2D point and draw it on the map within a pin annotation view. That’s what this part performs 🙂
That’s it, run the app and search for your town, your house address or your favourite place! Enjoy your work 🙂
As usual, here is the completed project for this tutorial. Feel free to comment below or tweet me, I am always looking to hear from you 😉
Update in response to @Kevin Thulin comment below:
In order to init the map with an explicit zoom level, you will need to specify a span values. To do so, place the following code inside the viewDidLoad method (right after the super.viewDidLoad() call):
// Init the zoom level let coordinate:CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 34.03, longitude: 118.14) let span = MKCoordinateSpanMake(100, 80) let region = MKCoordinateRegionMake(coordinate, span) self.mapView.setRegion(region, animated: true)
The code above will init the map to the East Asia region. Change the latitude/longitude of the coordinate constants above to modify the region, and change the values in the span constant to modify the zoom level to your preferences (a large span values results in a low zoom level, and a small span values reflect a high zoom level).
Hey yo, nice code.
But I got this problem using it: http://i.imgur.com/bcFUrHt.jpg any idea what could be? And thanks for the code ^^
Hi Bruno, probably your project deployment target is earlier than iOS 7. Can you double check? Otherwise, I may need more details about your code so I can help you 🙂
Malek
My deployment target is iOS 8.3 ._.
This is my mapViewController code: http://pastebin.com/41Vqm5sP , for some reason when i turn the iphone’s orientation the problem disappears >_<
first and second images are sequence, and third and fourth are another sequence
http://imgur.com/4Ro0Jw1,hLk5M0p,qRw65Ef,kGPa59g#0
by the way, sorry for my English, and thanks for the help ^^, I'm new to swift, and got almost no experience with obj-c ._.
Sounds like an iOS bug, if you try to hide navigation bar while search bar is shown, then moving from portrait to landscape will not result in such behavior. As a workaround, remove this line: searchController.hidesNavigationBarDuringPresentation = false
just did what you said, and now it only shows a bit of the search bar ._. http://imgur.com/zvlhzmh
Oh, the screenshot shows no navigation bar at all. Make sure the navigation bar is not hidden in storyboard (select the navigation controller->select attributes inspector–>check “Shows navigation bar”).
My navigation bar is not connected directly to the mapView, here is my storyboard: http://i.imgur.com/03gHSJk.png .
Well, in Deployment Info i just turn off landscape left and right and now is everything working well. Thanks for the code by the way ^^
Is there a way to init the map with a set zoom level? 🙂
Hi 🙂
I have updated the tutorial based on your comment, please check it above.
Dear sir.
It would seem that when I run your software, or when I
run the code I’ve written from your tutorial, I get an error from these
lines of code when I try to search for lesser known cities or when I
have to type in the full name of the location (i.e. Cairo, Egypt)…
self.pointAnnotation.coordinate = CLLocationCoordinate2D(latitude: localSearchResponse.boundingRegion.center.latitude, longitude: localSearchResponse.boundingRegion.center.longitude)
Instead of giving me the error code default of “does not exist” I get something like this…
Can
you figure out what is going on? I followed and typed your code just
the same. Thank you for your help.
Hi Dante 🙂
This is strange, I successfully tested the project with several address format for iOS 8 and even upgraded to the latest swift 2 without issues. Can you provide more of your code so I can help you better, or even attach your project or sample of it here so I take a better look on what is going on.
Can you send me you email address? I’ve tried to send you email before, yet it would not go through. Thank you.
Here’s the code I wrote following your example…
//
// ViewController.swift
// MapLocator
//
// Created by Dante Pettus on 8/5/15.
// Copyright (c) 2015 DSPEnterprisesLLC. All rights reserved.
//
import UIKit
import MapKit
import CoreLocation
//class ViewController: UIViewController, UISearchBarDelegate {
class ViewController: UIViewController, CLLocationManagerDelegate, UISearchBarDelegate {
var locationManager : CLLocationManager = CLLocationManager ()
var startLocation: CLLocation!
// code needed for search
var searchController : UISearchController!
var annotation : MKAnnotation!
var localSearchRequest : MKLocalSearchRequest!
var localSearch : MKLocalSearch!
var localSearchResponse : MKLocalSearchResponse!
var error : NSError!
var pointAnnotation : MKPointAnnotation!
var pinAnnotation : MKPinAnnotationView!
var pinAnnotationView : MKPinAnnotationView!
@IBAction func showSearchBar(sender: AnyObject) {
searchController = UISearchController(searchResultsController: nil)
searchController.hidesNavigationBarDuringPresentation = false
self.searchController.searchBar.delegate = self
presentViewController(searchController, animated: true, completion: nil)
}
@IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
mapView.showsUserLocation = true
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
startLocation = nil
//println(mapView)
let span = MKCoordinateSpanMake(100, 80)
//let region = MKCoordinateSpanMake(coordinate, span)
//self.mapView.setRegion(region, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
// 1
searchBar.resignFirstResponder()
dismissViewControllerAnimated(true, completion: nil)
if self.mapView.annotations.count != 0 {
annotation = self.mapView.annotations[0] as! MKAnnotation
self.mapView.removeAnnotation(annotation)
} // end of if self.mapView
//2
localSearchRequest = MKLocalSearchRequest()
localSearchRequest.naturalLanguageQuery = searchBar.text
localSearch = MKLocalSearch(request: localSearchRequest)
localSearch.startWithCompletionHandler{ (localSearchResponse, error) -> Void in
if localSearchResponse == nil{
var alert = UIAlertView(title: nil, message: “Place not found”, delegate: self,
cancelButtonTitle: “Try Again”)
alert.show()
return
}
} // end of localSearch.startsWithComplettionHandler
//3
self.pointAnnotation = MKPointAnnotation()
self.pointAnnotation.title = searchBar.text
/*
self.pointAnnotation.coordinate = CLLocationCoordinate2D(latitude: localSearchResponse.boundingRegion.center.latitude, longitude: localSearchResponse.boundingRegion.center.longitude)
*/
self.pointAnnotation.coordinate = CLLocationCoordinate2D(latitude: localSearchResponse.boundingRegion.center.latitude, longitude: localSearchResponse.boundingRegion.center.longitude)
self.pinAnnotationView = MKPinAnnotationView(annotation: self.pointAnnotation, reuseIdentifier: nil)
self.mapView.centerCoordinate = self.pointAnnotation.coordinate
self.mapView.addAnnotation(self.pinAnnotationView.annotation)
} // END OF SEARCHBARSEARCHBUTTON
}
//
// AppDelegate.swift
// MapLocator
//
// Created by Dante Pettus on 8/5/15.
// Copyright (c) 2015 DSPEnterprisesLLC. All rights reserved.
//
import UIKit
import CoreLocation
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var locationManager : CLLocationManager?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
locationManager = CLLocationManager()
locationManager?.requestWhenInUseAuthorization()
return true
}
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
my email is malek.isims88@gmail.com
hmm, I see your mistake. You need to move all the pointAnnotation initialisation code, as well as the mapView.centerCoordinate and the mapView.addAnnotation statements inside the startWithCompletionHandler block as I did in the tutorial above, because the block is running async and hence the pointAnnotation object should wait for it to return the localSearchResponse object 🙂
Wow…. I guess it was an easy mistake to make getting this intimate with Swift. Thanks for your help!!
You welcome 🙂
Hi!
Do you mind making a tutorial on shoving restaurant, bars, etc?
Loved the tutorial!
Hi Scott 🙂
Can you elaborate on your idea? what you would like exactly to see as features, etc ? what you want the tutorial to teach you exactly ?
Malek.
Yes, indeed:
-Tutorial on annotations showing different placed or POI’s. (Like a button to show different thins, f.example: Button for pubs, button for restaurants, etc)
-Tutorial 2.0 on shoing routes on a map from current location to the POI
-Tutorial on showing different types of maps (colors, styles, etc)
Thank you for your answer, Malek 🙂
You got it, I put your requests on my tutorial upcoming list, I will try hard to write them asap 🙂
Great tutorial!
I was wondering if you could add a section on displaying places near your current location without the mapView.
Thanks!
Hi Andrew 🙂
I am preparing another tutorial for this instead of a single section. Definitely on my tutorials list for the next week, stay tuned 😉
can you do the same for google maps and please integrate autocomplete places for the same..
thank you
I am having some issue and I cannot explain it, I have tried running through the tutorial and running your provided tutorial in Xcode 7, of course Xcode wants to update to the latest version of Swift witch I have down, but when I run the code every thing is fine ((zoom ect…) but as soon as I click on the “search” button everything stops working and I get no error and no search bar, what would be the cause of this? (Code Below)
import UIKit
import MapKit
class ViewController: UIViewController, UISearchBarDelegate {
var searchController:UISearchController!
var annotation:MKAnnotation!
var localSearchRequest:MKLocalSearchRequest!
var localSearch:MKLocalSearch!
var localSearchResponse:MKLocalSearchResponse!
var error:NSError!
var pointAnnotation:MKPointAnnotation!
var pinAnnotationView:MKPinAnnotationView!
@IBOutlet var mapView: MKMapView!
@IBAction func showSearchBar(sender: AnyObject) {
searchController = UISearchController(searchResultsController: nil)
searchController.hidesNavigationBarDuringPresentation = false
self.searchController.searchBar.delegate = self
presentViewController(searchController, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func searchBarSearchButtonClicked(searchBar: UISearchBar){
searchBar.resignFirstResponder()
dismissViewControllerAnimated(true, completion: nil)
if self.mapView.annotations.count != 0{
annotation = self.mapView.annotations[0]
self.mapView.removeAnnotation(annotation)
}
localSearchRequest = MKLocalSearchRequest()
localSearchRequest.naturalLanguageQuery = searchBar.text
localSearch = MKLocalSearch(request: localSearchRequest)
localSearch.startWithCompletionHandler { (localSearchResponse, error) -> Void in
self.pointAnnotation = MKPointAnnotation()
self.pointAnnotation.title = searchBar.text
self.pointAnnotation.coordinate = CLLocationCoordinate2D(latitude: (localSearchResponse?.boundingRegion.center.latitude)!, longitude: (localSearchResponse?.boundingRegion.center.longitude)!)
self.pinAnnotationView = MKPinAnnotationView(annotation: self.pointAnnotation, reuseIdentifier: nil)
self.mapView.centerCoordinate = self.pointAnnotation.coordinate
self.mapView.addAnnotation(self.pinAnnotationView.annotation!)
if localSearchResponse == nil{
let alert = UIAlertView(title: nil, message: “Place not found”, delegate: self, cancelButtonTitle: “Try again”)
alert.show()
return
}
}
}
}
Hi Damien, I replied to your email. Please catch any log errors you can so that I can help you better with your issue 🙂
Let me know how it goes
Hi Yogesh, you ask for it, you got it 🙂 http://sweettutos.com/2015/09/30/how-to-use-the-google-places-autocomplete-api-with-google-maps-sdk-on-ios/
Hello i get an error from this line of code:
annotation = self.mapView.annotations[0]
It says “Cannot assign a value of type ‘Any Object’ to a value of type ‘MKAnnotation!’ ”
Could u tell my why? Cant seem to get why
Hi Tim 🙂
This tutorial is updated for Xcode 7 and Swift 2.1, please make sure you are using Xcode 7. I just double check it and everything seems to be right.
Let me know.
Malek
What WOULD be the code for 1.2, I can’t update to 2.1. Unless I only need xcode 7 for it to compile.
Hi 🙂
I am afraid I cannot downgrade the code to 1.2 since I don’t work with Xcode 6 anymore. Please consider upgrading to Swift 2 with Xcode 7.
If you got any issues migrating to Swift 2, let me know, I’ll be glad to help.
This worked btw. Sorry for late answer. Thank you! I was wondering if u were thinking about writing about EventKit?
You looks kind of reading my mind. I am currently working on a calendar/reminder tutorial with Event Kit. Stay tuned 🙂
Wow you’re amazing! Will it be locationbased as well? Because ive worked in some extendt with the Event Kit but ive never rly found any good tutorial or explanations on the location based version. How u use the map like the reminder app does. But rly looking forward for this 😀
Hey again Malek, what if u want to give the user suggestions when it searches in like a tableview?
Hey again Malek, what if u want to give the user suggestions when it searches in like a tableview? Like it does in your google places autocomplete tutorial
Hey !!!
Amazing work done here …… hugely helpful…. Thank You so much for your hard work 🙂 . Much Appreciated !!
Thanks Cedan, you are welcome 🙂
Hey Tim 🙂
Unfortunately, Apple doesn’t seems to provide a search autocomplete API we can use to asynchronously fetch suggestions, as Google API does. If you want to go with native Apple APIs, then my advice is to rely on the textfield delegate method and try to fetch the array of places returned by MKLocalSearch each time the user types in some range of characters. Although I cannot guarantee top performance with such approach!
Btw, I will respond to you on your forum reply and your email by tomorrow, sorry for being late 🙁
I responded to you email. And i just want to show the user what kind of information they are searching for instead of “guessing” what place they want. Like some countries may have the same name for different streets in different cities. 🙂 Thank you again for ur help Malek. U are truly the best!
Hi Malek_T – Thank you for this tutorial. I’m looking to mess around with MapKit myself and this seems like a really good starting point.
I was wondering if you would be able / willing to run a quick tutorial on map overlays? The app i’m hoping to develop will take an area of the city marked out with lat/long co-ordinate points and mark these as “restricted areas” as part of a social game so any pointers would be hugely appreciated!
Thank you
Hi 🙂
I put your request on my to-do list. This is more likely to come out very soon as I am willing to get back writing about my favourite framework – MapKit.
Subscribe and stay tuned for the best to come!
Awesome! Thank you for the quick reply, subscribed and looking forward to the tut.
Just published 🙂
http://sweettutos.com/2015/12/06/swift-mapkit-tutorial-series-how-to-make-a-map-based-overlays/
Thanks Malek!
Two more teeny wee Q’s I’ll post one here as it is relevant to this tut and one on the other.
when I set the co ordinates to start in the UK (45.5 , -5.5) and search for Ayr, the pin is waaaay out from the town of Ayr yet the map app is spot on. Any way to fix that?
Thanks!
Hi Malek,
Tnx for the tutorial!
I’ve implemented the code in my app and at first everything seemed to be working.
But then sometimes when i do a search, the pin is placed at a seemingly random spot (i’m looking for a square in my hometown, but the pin gets dropped somewhere in the middle of the Atlantic Ocean).
I’ve downloaded your version that comes with this tutorial to test, but the same thing happened. Any ideas why this is happening?
I’m working with Xcode 7.1.1.
Thank you in advance! Joris
Hi LocVez, can you provide more details about your code? Let’s move to the Forum section where I will be glad to assist you to fix this and where all fellow readers can learn from our mistakes 🙂
Hi Joris 🙂
Can you debug the coordinates values of the pin before the self.mapView.addAnnotation statement. Exactly the pointAnnotation.coordinate longitude and latitude values. Also, how does your actual code look like ? Please provide more details and let’s move our discussion to the Forum section.
Hi Malek_T,
this is great and almost exactly what I was looking for.
I tried to extend this to have the pin draggable – but it does not work – could you please show me how to get the pin draggable?
I added
self.pinAnnotationView.draggable = true
but that does nothing )-:
Hi Thomas 🙂
I just wrote the solution in the forum section for you here: http://sweettutos.com/forums/topic/how-to-make-the-pin-draggable/
You basically need to set the draggable property from within the viewForAnnotation protocol method.
Hi Malek,
it works :-))
Now one can pin exactly to the birth location – e.g. inside a hospital 😉
This is marvellous – thank you so much!
You welcome, glad to help 🙂
Hi Malek_T – Thank you for this tutorial this is great and almost exactly what I was looking for. I am having some issue, i want to search places in country or city but it is not working i think i have a problem in my code
import UIKit
import MapKit
class ViewController: UIViewController, UISearchBarDelegate {
var searchController:UISearchController!
var annotation:MKAnnotation!
var localSearchRequest:MKLocalSearchRequest!
var localSearch:MKLocalSearch!
var localSearchResponse:MKLocalSearchResponse!
var error:NSError!
var pointAnnotation:MKPointAnnotation!
var pinAnnotationView:MKPinAnnotationView!
@IBAction func ShowSearchBar(sender: AnyObject) {
searchController = UISearchController(searchResultsController: nil)
searchController.hidesNavigationBarDuringPresentation = false
self.searchController.searchBar.delegate = self
presentViewController(searchController, animated: true, completion: nil)
}
func searchBarSearchButtonClicked(searchBar: UISearchBar){
searchBar.resignFirstResponder()
dismissViewControllerAnimated(true, completion: nil)
if self.mapView.annotations.count != 0{
annotation = self.mapView.annotations[0]
self.mapView.removeAnnotation(annotation)
}
//2
localSearchRequest = MKLocalSearchRequest()
localSearchRequest.naturalLanguageQuery = searchBar.text
localSearch = MKLocalSearch(request: localSearchRequest)
localSearch.startWithCompletionHandler { (localSearchResponse, error) -> Void in
if localSearchResponse == nil{
let alertController = UIAlertController(title: nil, message: “Place Not Found”, preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: “Dismiss”, style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alertController, animated: true, completion: nil)
return
}
self.pointAnnotation = MKPointAnnotation()
self.pointAnnotation.title = searchBar.text
self.pointAnnotation.coordinate = CLLocationCoordinate2D(latitude: localSearchResponse!.boundingRegion.center.latitude, longitude: localSearchResponse!.boundingRegion.center.longitude)
self.pinAnnotationView = MKPinAnnotationView(annotation: self.pointAnnotation, reuseIdentifier: nil)
self.mapView.centerCoordinate = self.pointAnnotation.coordinate
self.mapView.addAnnotation(self.pinAnnotationView.annotation!)
} }
@IBOutlet var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
} }
Hi Gopi 🙂
What kind of error you got? compiling or runtime ? Can you add the error description and probably even a stacktrace. Also, please open a forum thread with the error and code so that our fellow readers can benefit from help as well http://sweettutos.com/forums/forum/ios-development/
Thank you for the quick reply,Malek_T
when i was search the place in search bar it doesn’t display any thing. (that means i am searching for a one city name in search bar )
Thank you for the quick reply,Malek_T
when i was search the place in search bar it doesn’t display any thing. (that means i am searching for a one city name in search bar )
Hi Malek_T, truly fantastic tutorial. A really quick and easy way to get this sort of functionality into an app.
I was wondering if I might be able to get your assistance – I have two fields which the user would enter data into. One is a standard UILabel and one is the text entered into the Search Bar. I’m needing to pass this data from this initial view controller to a second ‘Confirmation’ page. I’ve been able to transfer the UILabel over very easily, but am having trouble accessing the text entered in the Search Bar. I’ve been looking through the documentation and having a bit of a head-scratching moment! Any ideas?
Thanks kindly
Seb
I coincidentally ran into the answer! For anyone trying to perform the functionality I’m trying to..
searchController.searchBar.Text! will get you what you need.
Found this top tutorial as well for showing data in different view controllers after being entered by the user – which may come in handy. Good luck – http://jamesleist.com/ios-swift-passing-data-between-viewcontrollers/
Seb
awesome
Thanks Mithilesh 🙂
Hello JFK I am also trying to do exactly the search suggestions like you. Can you kindly send me the link to your code so that I can refer it.
very good one…it is useful for me…but sir how to add suggestions to that search bar?could you please help me in doing that…
Hello Yasawi.
With Maleks help i ended up using Google search API and then using longitude and latitude and puting the pin on the apple map.
Is there any code done in apple default maps. I need to give suggestions as user types. Please help me if you know.
Nice Tutorial, easy to understand.
Can you write another one on shopping app like amazon?
Hey! nice Tutorial …
I would like to search my map annotations ..
hope you can help me thanks:)
Hey Dante it is so simple just put your code in else condition where you are checking if localresponse == nil
Hey nice piece of information but i am just wondering is there any possible way to display suggestions or autocomplete via api while typing.
Hello, thank you for this tuto, by cons I have two worries. The first is that the zoom is too wide, and when I change the value my application crashes. The second is that my search does not work, I stay on the same view. Do you have any idea of the problem? Thank you in advance
Hello thanks for this tutorial, I mixed this tutorial with that How to fully customize your Callout Annotations Card Views. All in all it works. By cons when I do a search in another city it delete an annotation to put it on the new city sought. I do not want the annotation to appear on the new city, because I wanted to personalize a part of a region but for the rest of the world I do not want it to have an annotation. Thanks for your feedback
Is it possible to just search a cetegory such as just searching for hotels?
Great tutorial! Works like a charm. Thanks.