Working with JSON
JavaScript Object Notation (JSON) has quickly become the preferred standard for exchanging data with web services.
JSON is easy for humans to read and write, and easy for machines to parse and generate. Most importantly, it is lightweight and compact which has led to its widespread adoption over XML, which can be very verbose.
ArcGIS Server provides both SOAP and REST based web services that expose mapping and geospatial capabilities to clients. Esri's web and mobile clients communicate with ArcGIS Server REST web services and exchange information with them using JSON.
JSON Library
The API uses the very popular, open-source json-framework to parse and generate JSON. Version 2.3 of json-framework is included with the ArcGIS library and available for you to use in your applications too. You don't need to download any additional libraries to handle JSON. Simply import ArcGIS.h header file, and start using the classes provided by json-framework.
The API classes, categories, category methods, and header files of the json-framework library included with the ArcGIS library have been namespaced with an "AGS" prefix to prevent conflicts if additional libraries in your project also bundle json-framework.
Consider the following example describing a person entity in JSON -
{
"firstName":"Jane",
"lastName":"Doe",
"age":27
}
The following code snippet shows how you can parse a json string into to an NSDictionary and access it's values -
//Quotes need to be escaped
NSString* person = @"{\"firstName\":\"Jane\",\"lastName\":\"Doe\",\"age\":27}";
//convert to json dictionary
NSDictionary* jsonDict = [person AGSJSONValue];
NSString* firstName = [jsonDict objectForKey:@"firstName"];
NSNumber* age = [jsonDict objectForKey:@"age"];
The following code snippet shows how you can convert a dictionary into a JSON string -
//dictionary from above
NSDictionary* jsonDict = ... ;
//convert back to json string
NSString* jsonStr = [jsonDict AGSJSONRepresentation];
ArcGIS classes are JSON friendly
Most classes in the API adopt the AGSCoding protocol. By doing so, they provide an easy to decode their state from JSON and encode their state to JSON. The JSON syntax for these classes is defined by the ArcGIS Server REST API.
The following code snippet shows how to convert JSON string for a point into an AGSPoint object and then back to a JSON string. The syntax for the JSON string is borrowed from the Geometry Objects section of the REST API documentation.
// from json string to object
NSString* jsonPoint = @"{ \"x\" : -118.4 , \"y\" : -45.2 , \"spatialReference\" : {\"wkid\" : 4326} }";
NSDictionary* json = [jsonPoint AGSJSONValue];
AGSPoint* point = [[AGSPoint alloc] initWithJSON:json];
// from object to json string
NSDictionary *json = [point encodeToJSON];
NSString* jsonString = [json AGSJSONRepresentation];
Invoking REST web services
While building iOS applications, you will often need to use web services. You may need to invoke your custom web services or REST based Server Object Extensions for ArcGIS Server to implement novel GIS capabilities in your application. Other times, you may rely on or 3'rd party web services such as Picasa or Yahoo to access photos, or retrieve weather information. Most of these web services are REST based and have the ability to return response in JSON.
The API makes it very convenient to invoke REST based web services that use JSON to exchange information. All you need to do is initialize an object of AGSJSONRequestOperation with a URL to the web service, and optionally a dictionary of parameters to send. If the web service is secured, you can also specify the credentials that should be used to access the web service.
//The URL of the webservice
NSURL* url = ...;
//The parameter to pass to the webservice
NSDictionary* params = ...;
AGSJSONRequestOperation* jsonOp = [[AGSJSONRequestOperation alloc] initWithURL:url queryParameters:params];
//The credentials to access the webservice with
jsonOp.credential = ...;
Next, set the target-action pair so that a method on one of your objects is invoked when the web service returns a response.
jsonOp.target = self;
jsonOp.action = @selector(operation:didSucceedWithResponse:);
It is also a good practice to set the errorAction so that your object is notified if an error is encountered while invoking the web service.
jsonOp.errorAction = @selector(operation:didFailWithError:);
Here is an example of how the action and error action methods could be implemented -
-(void) operation:(NSOperation*)op didSucceedWithResponse:(NSDictionary*)json{
//handle response
}
-(void) operation:(NSOperation*)op didFailWithError:(NSError*)error{
//handle error
}
Finally, add the AGSJSONRequestOperation object to an operation queue to invoke the web service request in the background.
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:jsonOp];
Behind the scenes, the operation will fire a request to the URL over an HTTP or HTTPS connection as specified in the URL. The operation will also automatically append the query parameters to the URL and include the authentication information, if provided, in the request header.
By default, the webservice is invoked using HTTP GET semantics, but if you want to use POST, you can do so by using the initWithURL:resource:queryParameters:doPOST: method while creating an AGSJSONRequestOperation object.