iOS: working with remote services

Gilles Grousset
Hack Like a Pirate
Published in
3 min readAug 30, 2011

When you design an iOS App it is most of the time a ‘connected’ App that interacts with a server to retrieve or post data.

However, there is no built-in way to enable remote communication in the iOS SDK, and everything has to be handled ‘by hand’ by the developer.

Most of the time iOS Apps talk with WebServices: SOAP/XML or REST/JSON. So I’m going to focus on them to explain what I usually use to make my Apps talk with remote services.

REST/JSON

Using REST with JSON data format is probably the easiest way to communicate with a remote server. All we have to do here is to initiate a HTTP connection ( NSURLConnection) and decode the JSON string as objects.

To encode/decode JSON data I use this nice library: http://stig.github.com/json-framework.

To run a synchronous HTTP connection use (retrieves my Twitter user data):

// Prepare requestNSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:@”http://api.twitter.com/1/users/show.json?screen_name=zippy1978"]cachePolicy:NSURLRequestUseProtocolCachePolicytimeoutInterval:60.0];// ResponseNSURLResponse *response;// ErrorNSError *error;// Synchronous connection, get result in NSDataNSData *data = [NSURLConnection sendSynchronousRequest:requestreturningResponse:&responseerror:&error];// Decode result as objectif (data && !error) {// Convert data as stringNSString *resultString = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];// Prepare JSON parserSBJsonParser *jsonParser = [[[SBJsonParser alloc] init] autorelease];//Decode// Returns the object represented by the passed-in string or nil on error. The// returned object can be a string, number, boolean, null, array or dictionary.NSDictionary *jsonResult = [jsonParser objectWithString:resultString error:&error];//Print Twitter user nameNSLog(@”User is %@”, [jsonResult objectForKey:@”name”]);} else {NSLog(@”Error !!”);}

A synchronous connection is nice, but if you run it like that in an App it will run on the main thread and so every UI update will hang until the connection has finished: this is not nice, and the user will probably think that the App has crashed.

In order not to block the main thread you can run the synchronous connection code in a separate NSThread or even better: run the connection asynchronously.

When connection is run asynchronously connection messages are sent to a delegate object.

To launch the connection asynchronously:

// Prepare requestNSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:@”http://api.twitter.com/1/users/show.json?screen_name=zippy1978"]cachePolicy:NSURLRequestUseProtocolCachePolicytimeoutInterval:60.0];// Prepare mutable data to receive resultNSMutableData *data = [[NSMutableData data] retain];// Run asynchronous connection with self as delegateNSURLConnection *connection = [[NSURLConnection connectionWithRequest:request delegate:self] retain];

Then we need to handle connection messages with delegate methods. First, we need to reset result data when connection received the initial response:

- (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)response {// Reset data[data setLength:0];}

We also need to handle new data received:

- (void)connection:(NSURLConnection *)aConnection didReceiveData:(NSData *)someData {// Append received data[data appendData:someData];}

Also, potential errors:

- (void)connection:(NSURLConnection *)aConnection didFailWithError:(NSError *)error {// Release connection[connection release];// Release data[data release];// LogNSLog(@”Error!!”);}

And finally when the connection completes:

- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection {// Convert data as stringNSString *resultString = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];// Prepare JSON parserSBJsonParser *jsonParser = [[[SBJsonParser alloc] init] autorelease];//Decode// Returns the object represented by the passed-in string or nil on error. The// returned object can be a string, number, boolean, null, array or dictionary.NSDictionary *jsonResult = [jsonParser objectWithString:resultString error:&error];//Print Twitter user nameNSLog(@”User is %@”, [jsonResult objectForKey:@”name”]);// Release[connection release];[data release];}

SOAP/XML

Working with REST/JSON remote services is not that hard. However, sometimes we have to use SOAP: SOAP is strict, and SOAP is XML.

As there is no built-in support for SOAP in iOS SDK, you need to handle everything by hand: post XML parameters and parse XML responses to populate objects.

Doing all that by hand can be very, very long (if you have already tried NSXMLParser you probably know what I mean).

Hopefully, like there is Axis for Java, there is WSDL2ObjC ( http://code.google.com/p/wsdl2objc) for Objective-C: a code generator to handle SOAP services with Objective-C classes.

WSDL2ObjC has a GUI where you just need to provide a WSDL file and an output folder. When you click on the Parse WSDL button classes are generated into the output folder.

To work with the generated classes you add them to an XCode project, but you also need to link the code against the libxml2 C library.

Just like with a NSURLConnection, generated SOAP classes can run synchronoulsy or asynchronously.

For more detailed instructions and sample code, just go here: http://code.google.com/p/wsdl2objc/wiki/UsageInstructions.

I hope this will help some of you…

Originally published at https://blog.grousset.fr on August 30, 2011.

--

--