Skip To Content

Access feature data in the cloud

In this topic

This topic describes how to build an iOS application to consume feature data from the cloud. It's assumed that you've already added a map to your application as described in Adding a map to your app.

The API provides a feature layer (class name AGSFeatureLayer) that allows you to access and edit vector map data. The layer depends on ArcGIS feature services, which provide access to the data, accept and persist edits, and allow the layer to filter data using SQL-like queries. The feature services can be hosted on ArcGIS Online (Esri's cloud) or on your on-premise servers. In this topic, you'll be using a feature service on ArcGIS Online.

Learn more about feature layers

1. Add data from a feature service

Adding data from a feature service is as simple as instantiating a feature layer and adding it to your map. To instantiate the layer, all you need is a URL to the feature service you're going to use, and optionally, the user credentials to access that service. The service you're using in this topic is public, so you do not need to provide any credentials. After adding the layer to the map, you'll customize the symbology of the layer to display its data as blue dots on the map.

override func viewDidLoad() {
 super.viewDidLoad()

 //code from previous tutorial to add a basemap tiled layer
 let url = NSURL(string: "http://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer")
 let tiledLayer = AGSTiledMapServiceLayer(URL: url)
 self.mapView.addMapLayer(tiledLayer, withName: "Basemap Tiled Layer")
 //Set the map view's layer delegate
 self.mapView.layerDelegate = self

 //CLOUD DATA
 let featureLayerURL = NSURL(string: "http://services.arcgis.com/P3ePLMYs2RVChkJx/ArcGIS/rest/services/World_Cities/FeatureServer/0")
 let featureLayer = AGSFeatureLayer(URL: featureLayerURL, mode: .OnDemand)
 self.mapView.addMapLayer(featureLayer, withName: "CloudData")

 //SYMBOLOGY
 let featureSymbol = AGSSimpleMarkerSymbol(color:UIColor(red: 0, green: 0.46, blue: 0.68, alpha: 1))
 featureSymbol.size = CGSizeMake(7, 7)
 featureSymbol.style = .Circle
 featureSymbol.outline = nil
 featureLayer.renderer = AGSSimpleRenderer(symbol: featureSymbol)

}

2. Allow a user to select features

In this section, you'll allow a user to select a country from a list. To do this, you'll add a button to the UI and connect the button's Touch Up Inside event to an action method on the view controller called showCountryPicker:.

When a user taps the button, the view controller's method showCountryPicker: will be invoked. In this method, you'll instantiate UIPickerView and display it on screen. To add a list of countries to the picker, you'll set the view controller as the picker's data source and implement the methods defined in the UIPickerViewDataSource protocol. Finally, you'll also set the view controller as the picker's delegate and implement the pickerView:didSelectRow:inComponent: method defined in the UIPickerViewDelegate protocol to allow the picker to inform you when a user selects a country.

//show picker view
@IBAction func showCountryPicker(sender:AnyObject) {
 //create the picker view for the first time
 if self.countryPicker == nil {
  self.countryPicker = UIPickerView()
  self.countryPicker.delegate = self
  self.countryPicker.dataSource = self
  self.countryPicker.showsSelectionIndicator = true
  self.countryPicker.backgroundColor = UIColor.whiteColor()
  self.view.addSubview(self.countryPicker)
  self.countryPicker.setTranslatesAutoresizingMaskIntoConstraints(false)
  //add auto-layout constraints to properly position the picker
  var views = NSMutableDictionary()
  views.setValue(self.countryPicker, forKey: "countryPicker")
  self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[countryPicker]|", options: nil, metrics: nil, views: views))
  self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[countryPicker]|", options: nil, metrics: nil, views: views))
 }
 self.countryPicker.hidden = false
}

func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
 return 1
}

func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
 return self.countries.count
}

func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
 return self.countries[row]
}

3. Display selected features

In this section, you'll highlight the features that belong to the country selected by the user.

First, you'll get the country selected by the user. If the user selected None, clear any selection on the feature layer. Otherwise, select features using the SQL-like statement COUNTRY = <selected_country>. Before you perform the selection, you need to set the selection symbol so that selected features are symbolized with red dots on the map. You also need to set the view controller as the feature layer's queryDelegate. This will allow the view controller to respond when the selection is complete. As part of being the query delegate, the view controller needs to adopt the AGSFeatureLayerQueryDelegate protocol and implement the methods defined in that protocol that are relevant.

func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {

 let countryName = self.countries[row]
 let featureLayer = self.mapView.mapLayerForName("CloudData") as AGSFeatureLayer

 if featureLayer.selectionSymbol == nil {
  //SYMBOLOGY FOR WHERE CLAUSE SELECTION
  let selectedFeatureSymbol = AGSSimpleMarkerSymbol()
  selectedFeatureSymbol.style = .Circle 
  selectedFeatureSymbol.color = UIColor(red: 0.78, green: 0.3, blue: 0.19, alpha: 1)
  selectedFeatureSymbol.size = CGSizeMake(10, 10)
  featureLayer.selectionSymbol = selectedFeatureSymbol
 }

 if featureLayer.queryDelegate == nil {
  featureLayer.queryDelegate = self
 }
 
 if countryName == "None" {
  //CLEAR SELECTION
  featureLayer.clearSelection()
 }
 else {
  //SELECT DATA WITH WHERE CLAUSE
  let selectQuery = AGSQuery()
  let queryString = "CNTRY_NAME = '\(countryName)'"
  selectQuery.whereClause = queryString
  featureLayer.selectFeaturesWithQuery(selectQuery, selectionMethod: .New)
 }

 //DISMISS PICKER
 self.countryPicker.hidden = true

}

When the selection operation is complete, the view controller's featureLayer:operation:didSelectFeaturesWithFeatureSet: method will be invoked. In this method, you'll iterate through the selected features and create a minimum bounding envelope that covers all these features. You'll then zoom the map to this envelope.

func featureLayer(featureLayer: AGSFeatureLayer!, operation op: NSOperation!, didSelectFeaturesWithFeatureSet featureSet: AGSFeatureSet!) {

 //ZOOM TO SELECTED DATA
 var env:AGSMutableEnvelope!
 for selectedFeature in featureSet.features as [AGSGraphic]{
  if env != nil {
   env.unionWithEnvelope(selectedFeature.geometry.envelope)
  }
  else {
   env = selectedFeature.geometry.envelope.mutableCopy() as AGSMutableEnvelope
  }
 }
 self.mapView.zoomToGeometry(env, withPadding: 20, animated: true)
}

4. Run the application

At this point, you've written all the code required to load data from a feature service and allow a user to highlight features that belong to a country. Now you need to declare the properties you've been using as well as the delegate protocols you've adopted. You do this in the view controller's swift file.

class ViewController: UIViewController, AGSMapViewLayerDelegate, UIPickerViewDelegate, UIPickerViewDataSource, AGSFeatureLayerQueryDelegate {

 @IBOutlet weak var mapView: AGSMapView!
 let countries = ["None", "US", "Canada", "France", "Australia", "Brazil"]
 var countryPicker: UIPickerView!
 
 ...

}