ArcGIS Feature Layer

An ArcGIS Feature Layer displays features from a layer of an ArcGIS Server Feature Service or an ArcGIS Server Map Service. You can perform queries and selections on features, and work with feature attachments. When using an ArcGIS Server Feature Service, you can also edit features and their attachments. The feature layer honors defintion queries, scale dependencies, and other properties configured on the service layer.

Feature Services, like Map Services, are based on map documents (*.mxd and *.msd files). A map document contains references to GIS datasets. These datasets contain the features that need to displayed in the map. Features are real world entities such as buildings, pipes, and parcels. Features are organized into layers in a map document. For example, the map document of a national park may contain separate layers for hiking trails, picnic areas and campgrounds. Map documents can be published to ArcGIS Server to create Map and Feature services.

ArcGIS Server Map and Feature services are accessible on the web as SOAP and REST web services. You can find the URL of these web services using the ArcGIS Server Services Directory.

The feature layer retrieves features from the service layer, holds them in memory on the device, and then draws them onto the map using the device's graphics capabilities. This is different from a dynamic layer or a tiled layer which rely on the service to render features into images which are then displayed on the map. Whenever you navigate the map, dynamic and tiled layers fetch new map images to display, but the feature layer may already have all the features it needs to display, or it may fetch some more features. In some cases, a feature layer can be more efficient than a dynamic or tiled layer because it does not have to make frequent round trips to the server.

Displaying features

The feature layer inherits its drawing capabilities from the graphics layer. Thus, in a way, they both provide the same functionality for displaying features. However, one key difference is that the graphics layer requires you to provide the graphics that need to be displayed, whereas the feature layer automatically retrieves them from the service layer. Thus, you should never directly add or remove any graphics from the feature layer like you do with the graphics layer.

Another difference is that the graphics layer requires you to provide either a renderer or the symbols needed for displaying the graphics, whereas the feature layer inherits its symbology from the service layer when the service is hosted on an ArcGIS Server 10 or above. If the service is from an older server, you will need to assign a renderer for the feature layer to symbolize the features.

To instantiate a feature layer, you need to provide a URL to a layer in a Map Service or Feature Service REST endpoint. This URL is usually of the form http://<server:port>/<instance>/rest/services/<service>/MapServer/<layerid> or http://<server:port>/<instance>/rest/services/<service>/FeatureServer/<layerid>

You also need to specify a mode while creating the feature layer. The mode decides how the layer will retrieve features from the service layer.

NSURL* url = [NSURL URLWithString: @"http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/0"]; 	 
AGSFeatureLayer* featureLayer = [AGSFeatureLayer featureServiceLayerWithURL: url mode: AGSFeatureLayerModeOnDemand];

Snapshot mode

In snapshot mode, all features belonging to the service layer are retrieved when the feature layer is loaded. This mode is useful only if the number of features is reasonably small. iOS applications are constrained by the amount of memory available to them on a device, and it is not practical to hold large numbers of features in memory. The number of features actually retrieved depends upon the limits set on the service. By default, ArcGIS Server 10 services only allow1000 features to be retrieved, but this could be configured differently by the server administrator. Once the features are retrieved, the layer does not request more features from the service.

On-Demand mode

In on-demand mode, only features within the map's extent are retrieved from the service layer when the feature layer is loaded. As the user navigates the map, the layer fetches more features for subsequent map extents. Thus, at any time, only those features that need to be displayed are retrieved.

You can customize, to a certain degree, how many and how often features are fetched from the service by adjusting the layer's bufferFactor and expirationInterval properties. The buffer factor allows the layer to fetch more features than just those that are within the current map extent. For instance, a buffer factor of 2 would allow the layer to fetch features that are within an extent twice as large as the current extent. This could help reduce network requests if subsequent extents fall within the buffered extent. Features will only be fetched when the map's extent goes beyond the buffered extent. The expiration interval forces the layer to re-fetch features that were fetched before the specified interval. This is useful if the data in the service changes frequently and you don't want the layer to display stale features. TheautoRefreshOnExpiration property allows you to specify whether the features should be fetched as soon as the expiration interval elapses, or wait until the user navigates the map.

This mode could potentially require more network requests than Snapshot mode because features may be fetched every time you navigate the map. But it also has the potential to use less memory than Snapshot mode as long as the map extents require only a subset of features to fetched from the service layer.

Selection mode

In selection mode, no features are retrieved when the layer is loaded. Features are retrieved when selection operations are performed. Thus, only those features that are displayed as selected are ever retrieved from the service. This mode is useful if you want to only retrieve specific features and highlight them on the map. You would typically use a feature layer in selection mode on top of a dynamic layer using the same service. Features would normally be displayed by the dynamic layer and the feature layer would be empty. When the user wants to edit some features, a selection operation would be performed on the feature layer and the resulting features would be displayed as selected. User would edit the selected features, and then the selected features would be cleared. The feature layer would go back to being empty and the updated features would be displayed by the dynamic layer.

Selecting features

When the feature layer is operating in Selection mode, you can perform selection operations which retrieve features from the service and display them on the map. The features are displayed using the layer's selection symbol. If the selection symbol is not defined, the layer's renderer is used. It is recommended you specify a selection symbol to make the selected features appear highlighted and stand out from the remaining features.

AGSSimpleMarkerSymbol* cyanSquare = [AGSSimpleMarkerSymbol simpleMarkerSymbolWithColor:[UIColor cyanColor]];
cyanSquare.style = AGSSimpleMarkerSymbolStyleSquare;
cyanSquare.size = 18;
featureLayer.selectionSymbol = cyanSquare;

You perform selections using selectFeaturesWithQuery:selectionMethod: by providing a selection query and a selection method. The selection query can be based on attribute relationships, or spatial relationships, or both. For e.g. selecting all cities that have a population greater than 100,000 and within the state of California. The selection method specifies whether the features satisfying the relationships should be added to the existing set of selected features, removed from the set, or entirely replace the set.

AGSQuery* query = [AGSQuery query]; 
query.where = @"POPULATION > 100000";
query.spatialRelationship = AGSQuerySpatialRelationshipWithin; 
query.geometry = californiaGeometry;  
[featureLayer selectFeaturesWithQuery:query selectionMethod:AGSFeatureLayerSelectionMethodAdd];

The complete set of selected features is accessible through the selectedFeatures property on the layer. Do not add or remove features to the set directly, instead use selection operations as described above.

When you no longer want to display the selected features, you can remove them using clearSelection.

Querying features

As discussed previously, the feature layer automatically retrieves features which need to be displayed on the map. But the layer also provides the ability to retrieve additional features using queries. Queries can be based on attribute relationships, spatial relationships, or both. Queries can return whole features, just the feature identifiers, or even related features. The querying capabilities of a feature layer are very similar to that of AGSQueryTask. The pattern of performing queries is also the same. The feature layer informs its queryDelegate when queries complete successfully or encounter errors. You should set one of your classes as the queryDelegate to receive this information.

Editing features

When the feature layer displays features an ArcGIS Feature Service (as opposed to a Map Service), you can make changes to those features, delete them, or add new features to the service. However, it is possible that that the server administrator may have disabled the editing capability of the Feature service. It is always a good idea to make sure that the layer is editable before making any edits. You can easily find out if a layer is editable by looking for edit operations on the Services Directory page for the Feature Service layer.

Feature Layer Operations

You can also programmatically check if a layer is editable by inspecting the editable property as follows -

if(!featureLayer.editable){
 NSLog(@"Layer does not support editing");
 //bail out
}

To modify an existing feature, you need a reference to the corresponding AGSGraphic object. You can get the graphic in a variety of ways. For instance, in response to a user tap on the map, or by iterating through the graphics collection of the layer looking for a graphic with some particular attribute values. If you know the OBJECTID of the feature you're looking for, you can find its corresponding graphic by using the convenience method lookupFeatureWithObjectId:

Once you have a reference to the graphic, you can make changes to its geometry or attributes. But these changes are only applied on the device, the service remains unmodified. Once you are ready to post your changes to the service, you need to call updateFeatures:

//modify the graphic  
AGSGraphic* graphic = ... ; 
graphic.geometry = newGeometry; 
[graphic.attributes setValue:@"<new-value>" forKey:@"<field-name>"];  

...

//update the service 
[featureLayer updateFeatures:[NSArray arrayWithObject:graphic]];

The feature layer informs its editingDelegate when edit operations succeed or encounter errors. You should set one of your classes as the feature layer's editingDelegate to receive results of successful operations and to handle any errors.

To delete features, you can use deleteFeaturesWithObjectIds: passing in an array of OBJECTIDs of features which need to be deleted. Or you can delete features based on attribute or spatial relationships using deleteFeaturesWithWhereClause:geometry:spatialRelation: In both cases, features are removed from the layer and the service.

[featureLayer deleteFeaturesWithWhereClause:@"<field-name> = <value>" geometry:nil spatialRelation:nil];

To add a new feature, you first need to construct a graphic for it. To construct a graphic, you need to specify a feature type or a feature template.

Features in a layer could be of many types. For e.g. schools could be of type public or private. Each type might be displayed with a different symbol on the map. To create a new school feature, you would need to specify its type -- whether it should be a public school or a private school.

A feature template provides default settings for a feature, for e.g. its attribute values. Templates make it easy to create new features. A layer could have multiple templates. Or if the layer has feature types, each type could have one or more templates .Feature types and Feature templates are defined by the service and are available on the layer through the types and templates properties.

AGSFeatureType* privateSchool = [featureLayer.types objectAtIndex:index];  
AGSGraphic* newSchool = [featureLayer featureWithType:privateSchool];

Even when you have constructed the graphic, note that it is still not added to the layer and hence, won't be displayed on the map. If you are ready to add the feature to the service, you need to call addFeatures: . When this operation succeeds, the graphic will automatically be added to the feature layer and displayed on the map.

[featureLayer addFeatures:[NSArray arrayWithObject:newSchool]];

If you do not want to immediately persist the graphic to the feature service, you can manually add it to the feature layer's graphics collection by using addGraphic:. If the graphic has a valid geometry, it will be displayed by the map. Then later you can call addFeatures: to persist the graphic to the service. In the even that you decide not to persist the graphic, you will need to manually remove it from the feature layer by using removeGraphic:

Each add, delete, and update operation is performed over a separate network request. If you are performing a large number of edits, it will be expensive to perform them as separate operations. When possible, it is more efficient to perform all edits in a batch over a single network request using applyEditsWithFeaturesToAdd:toUpdate:toDelete:

Working with attachments

Features in a layer may have attachments. Attachments could be of various types such as pictures, documents, videos, etc. For e.g. a house may have an image of its blueprint, or a parcel may have a title deed document. Before trying to access or edit attachments, you should make sure that the layer supports attachments. This information is listed in the Services Directory for the Feature Service layer.

Feature Service Layer attachments property
You can also programmatically check whether the layer supports attachments by inspecting the attachments property as follows -
if(!featureLayer.attachments){
  NSLog(@"Layer does not support attachments");
  //bail out
}

To get attachments for a particular feature, you first need to find out if that feature has any attachments. You do this by calling queryAttachmentInfosForObjectId: which fetches metadata about the feature's attachments. The metadata includes information such at the content type, name, and a unique identifier for each attachment.

//OBJECTID of a feature
int oid = ...;

[featureLayer queryAttachmentInfosForObjectId: oid];

The feature layer informs its editingDelegate when operations related to attachments succeed or encounter errors. You should set one of your classes as the feature layer's editingDelegate to receive results of successful operations and to handle any errors.

The following code snippet shows the implementation of the delegate method which receives attachment metadata.

- (void) featureLayer:(AGSFeatureLayer *) featureLayer
operation :(NSOperation*) op
didQueryAttachmentInfosWithResults:(NSArray *) attachmentInfos {

	NSLog(@"Attachment Count : %d",[attachmentInfos count]);
	for (AGSAttachmentInfo* attInfo in attachmentInfos) {
         NSLog(@"Attachment ID : %d", attInfo.attachmentId);
		}
}
Once you know that the feature has attachments, you can use retrieveAttachmentForObjectId:attachmentId: to fetch a particular attachment by providing its unique identifier.

If the layer is editable, you can also delete attachments using deleteAttachmentsForObjectId:attachmentIds: , add new attachments using addAttachment:filepath: or addAttachment:data:filename: , or replace existing attachments using updateAttachment:data:filename:attachmentId: .

The AGSAttachmentManager greatly simplies working with attachments by providing a high-level, coarse grained API on top of the functionality provided by the feature layer. Refer to Working with the Attachment Manager for more information.

See also

5/9/2012