In this tutorial, we are going to implement the address search feature using OneMap REST API. If you want to know more about OneMap, please visit to OneMap API Help page.
We will continue our tutorial from my post how to add OneMap to iOS App, in which I’ve shown how to use ArcGIS iOS SDK and adding OneMap base map and setting map extent. Complete the steps in it before attempting this tutorial.
We are going to call the Address Search REST API from OneMap form our iOS app. I’ve tried out the API call and explored the data returned from the service in previous post Exploring OneMap REST API with Swift Playgrounds.
Add Navigation Controller
First, we need to add Navigation controller to our View Controller. Go to Editor > Embed In > Navigation Controller. A Navigation Controller is added to our View Controller.
Add UISearchController And UITableViewController
We are going to use the UISearchController to allow users to key in address. The results will be shown in UITableViewController as the user type in the key words. Add UISearchController property and UITableViewController property in the View Controller.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var resultTableViewController = UITableViewController() | |
var searchController = UISearchController() |
In the viewDidLoad( ) method, add following setup code for UISearchController.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// UISearchController Setup | |
searchController = UISearchController(searchResultsController: resultTableViewController) | |
searchController.searchResultsUpdater = self | |
searchController.searchBar.searchBarStyle = UISearchBarStyle.Minimal | |
searchController.hidesNavigationBarDuringPresentation = false | |
navigationItem.titleView = searchController.searchBar | |
definesPresentationContext = true | |
resultTableViewController.tableView.dataSource = self | |
resultTableViewController.tableView.delegate = self | |
searchController.dimsBackgroundDuringPresentation = false | |
searchController.delegate = self | |
searchController.searchBar.delegate = self |
Next, add the necessary delegates to View Controller as follow:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// delegates for AGSMapViewLayer, UISearchController, UITableView | |
class ViewController: UIViewController, AGSMapViewLayerDelegate, | |
UISearchResultsUpdating, UITableViewDelegate, | |
UITableViewDataSource, UISearchControllerDelegate, | |
UISearchBarDelegate { … |
Create a data structure to hold the address data
Create a structure named Place to hold address name, category, X and Y.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct Place { | |
var placeName = "" | |
var Category = "" | |
var X = 0.0 | |
var Y = 0.0 | |
} |
In ViewController, declare an array of Places. This array will be our data model to store the search results.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var searchResults = [Place]() |
Implement UITableView delegate protocol methods
There are three protocol methods we need to implement to adopt the UITableView delegate protocol. Add the following methods to ViewController Class.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// UITableView delegate protocol methods | |
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { | |
searchController.searchBar.text = searchResults[indexPath.row].placeName | |
showSelectedSearchPlace(searchResults[indexPath.row]) | |
} | |
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { | |
let rowData = searchResults[indexPath.row].placeName | |
let cell = UITableViewCell() | |
cell.textLabel?.text = rowData | |
return cell | |
} | |
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | |
return searchResults.count | |
} |
Implement UISearchResultsUpdating delegate protocol method
UISearchResultsUpdating protocol requires to implement the following method. This allow us to update search results based on the information users enters in the search bar.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func updateSearchResultsForSearchController(searchController: UISearchController) { | |
getAddresses(searchController.searchBar.text) | |
} |
Next, we will implement the function to call OneMap REST API to search for the address.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Call OneMap's Address Search API to search a location in Singapore | |
func getAddresses(keyWord: String ){ | |
if keyWord != "" { | |
let keyWordEscaped = keyWord.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) | |
let urlString = "http://www.onemap.sg/API/services.svc/basicSearch?token=qo/s2TnSUmfLz+32CvLC4RMVkzEFYjxqyti1KhByvEacEdMWBpCuSSQ+IFRT84QjGPBCuz/cBom8PfSm3GjEsGc8PkdEEOEr&wc=SEARCHVAL%20LIKE%20%27\(keyWordEscaped!)$%27&otptFlds=CATEGORY&returnGeom=0&nohaxr=10" | |
session.dataTaskWithURL(NSURL(string: urlString)!, completionHandler: { | |
(taskData, taskResponse, taskError) -> Void in | |
var jsonReadError : NSError? | |
var jsonResult = NSJSONSerialization.JSONObjectWithData(taskData, options: NSJSONReadingOptions.MutableContainers, error: &jsonReadError) as NSDictionary | |
let resultsArray = jsonResult["SearchResults"] as NSArray | |
self.searchResults = [] | |
for (index, result) in enumerate(resultsArray){ | |
if index > 0 { | |
var place = Place() | |
if let placeName = result["SEARCHVAL"] as String? { | |
place.placeName = placeName | |
} | |
if let category = result["CATEGORY"] as String? { | |
place.Category = category | |
} | |
if let x = result["X"] as NSString? { | |
place.X = x.doubleValue | |
} | |
if let y = result["Y"] as NSString? { | |
place.Y = y.doubleValue | |
} | |
self.searchResults.append(place) | |
} | |
} | |
self.resultTableViewController.tableView.reloadData() | |
}).resume() | |
} | |
} |
Run the application
If everything goes well, a search bar will be displayed on the navigation controller title place.
When the user type in the search keywords in the search bar, getAddresses function is called and a list of addresses started by the keyword is shown in the table view as suggestion.
Show the selected one on the map view
We need to implement one more function to show the search result when the user clicks on one of the suggested places. This function is called in tableView:didSelectRowAtIndexPath: delegate method.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func showSelectedSearchPlace(selectedPlace :Place){ | |
// to close suggested list when the user selected one | |
searchController.active = false | |
searchController.searchBar.text = selectedPlace.placeName | |
// a red color symbol to mark the place | |
let myMarkerSymbol = AGSSimpleMarkerSymbol() | |
myMarkerSymbol.color = UIColor.redColor() | |
// a point representing x,y data from selctedPlace | |
let point = AGSPoint(x: selectedPlace.X, y: selectedPlace.Y, spatialReference: mapView.spatialReference) | |
// make the selectedPlace at the center of the map | |
mapView.centerAtPoint(point, animated: false) | |
// make a graphic with symbol and point to add to the map | |
var pointGraphic = AGSGraphic(geometry: point, symbol: myMarkerSymbol, attributes: nil) | |
// remove previously searched places | |
graphicLayer.removeAllGraphics() | |
// display the graphic on the map | |
graphicLayer.addGraphic(pointGraphic) | |
} |
Above screen is shown when the user selects City Hall from suggested addresses. The project is available on github. Please leave comments if you have any questions and suggestion.
Reblogged this on Dinesh Ram Kali..
LikeLike