Connecting to a php service from iOS

2012-08-26 Updated 2025-12-31 · dc272e6

Deprecated Time has moved on , IOS has moved forward to the point where this is no longer a supported way of doing things Connecting to a web service is a requirement for many iOS applications , especially in the enterprise. In this tutorial , I will be covering how to connect to a web service that returns and handles JSON formatted data. I prefer JSON as it is easier to convert to objects native to the relative language both server and client side. NOTE: For the Objective-C portion of this tutorial , I will be using a(very tiny) Library of my own creation called * JSONDictionaryExtensions* for converting JSON data to and from an NSDictionary , you can get hold of it here . PHP Here I have created a simple php script that will provide the necessary services to test the tutorial application. I will not go over this code in detail here because I assume that anyone reading this will ether not care about what it does because all they are trying to do is learn how to connect to a service,or already able to understand it ,in which case the comments should suffice. All that you need to know here is that the tasks the service performs are selected by the value of the 'METHOD' http header fields.

<?php
/*Simple Service
This is just a simple php script that will return values ,the 
method is selected using the value of HTTP_METHOD
*/
if ($_SERVER['HTTP_METHOD'] === 'getValues'){
//just return some test values
$data['value1'] = 1;
$data['value2'] = "Hello php service world";
echo json_encode($data);
}
else if ($_SERVER['HTTP_METHOD'] === 'postValues'){ 
$body;
/*Sometimes the body data is attached in raw form and is not attached 
to $_POST, this needs to be handled*/
if($_POST == null){
$handle  = fopen('php://input', 'r');
$rawData = fgets($handle);
$body = json_decode($rawData);
}
else{
$body == $_POST;
}
echo json_encode($body);//just return the post you sent it for testing purposes
}
else {
$data['error'] = 'The Service you asked for was not recognized';
echo json_encode($data);
}
?>

So all you have to do is copy and save it as * [what ever you want].php *in your web server. Now browse to it to make sure its working alright, I placed mine in my sites directory so my path and the path I will be referring to for the service is: *http://localhost/~divanvisagie/SimpleService/index.php * You should get the following output as a result: {"error":"The Service you asked for was not recognized"} Don't worry about the error,thats just because we havent sent the service any headers to tell it what to do. Objective-C For the sake of the tutorial , I will create a simple single view iPhone app that will connect to the service: screenshot Next I create a class called ServiceConnector which inherits from NSObject,this class will be doing all of our connection and request management. First we set up the class's header ,so go to ServiceConnector.h . We know we will be calling these request methods from a ViewController and we also know that we will need the data returned to the ViewController in order to display it. so lets set up some protocols for sending messages to the delegate.

@protocol ServiceConnectorDelegate <NSObject>
-(void)requestReturnedData:(NSData*)data;
@end

We also need to make sure that ServiceConnector listens to NSURLConnection and we will aslo set up the rest of the interface,here is the whole of ServiceConnector.m:

//
//  ServiceConnector.h
//  Service Reader
//
//  Created by Divan Visagie on 2012/08/25.
//
#import <Foundation/Foundation.h>
@protocol ServiceConnectorDelegate <NSObject>
-(void)requestReturnedData:(NSData*)data;
@end
@interface ServiceConnector : NSObject <NSURLConnectionDelegate,NSURLConnectionDataDelegate>
@property (strong,nonatomic) id <ServiceConnectorDelegate> delegate;
-(void)getTest;
-(void)postTest;
@end

Now lets move on to ServiceConnector.m and set up the interface, we set up a variable in which to store the received data...

@implementation ServiceConnector{
NSData *receivedData;;
}

..then we implement the getTest method.As you should be able to tell my the name , this method will test the GET functionality on our php script. First we build a request and assign it the required headers , then we create an NSURLConnection that will perform the request and return data in its delegate methods.Please note again that this URL will only apply to me (heck my name is in it its that custom), so you will need to replace that with whatever your service URL is.

-(void)getTest{
//build up the request that is to be sent to the server
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL    URLWithString:@"http://localhost/~divanvisagie/SimpleService/index.php"]];
[request setHTTPMethod:@"GET"];
[request addValue:@"getValues" forHTTPHeaderField:@"METHOD"]; //selects what task the server will perform
//initialize an NSURLConnection  with the request
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(!connection){
NSLog(@"Connection Failed");
}
}

Next is the postTest method , the code may look longer , but it is actually pretty much the same thing(replacing setHTTPMethod:@"GET" for @"POST") of corse. The reason it looks longer is because we have to build up some sample data to attach to the body of the post:

-(void)postTest{
//build up the request that is to be sent to the server
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://localhost/~divanvisagie/SimpleService/index.php"]];
[request setHTTPMethod:@"POST"];
[request addValue:@"postValues" forHTTPHeaderField:@"METHOD"];
//create data that will be sent in the post
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setValue:@2 forKey:@"value1"];
[dictionary setValue:@"This was sent from ios to server" forKey:@"value2"];
//serialize the dictionary data as json
NSData *data = [[dictionary copy] JSONValue];
[request setHTTPBody:data]; //set the data as the post body
[request addValue:[NSString stringWithFormat:@"%d",data.length] forHTTPHeaderField:@"Content-Length"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(!connection){
NSLog(@"Connection Failed");
}
}

Now that thats done all we have to do is handle what is sent back with NSURLConnections delegate methods.

#pragma mark - Data connection delegate -
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ // executed when the connection receives data
receivedData = data;
/* NOTE: if you are working with large data , it may be better to set recievedData as NSMutableData 
and use  [receivedData append:Data] here, in this event you should also set recievedData to nil
when you are done working with it or any new data received could end up just appending to the 
last message received*/
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ //executed when the connection fails
NSLog(@"Connection failed with error: %@",error.localizedDescription);
}
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
/*This message is sent when there is an authentication challenge ,our server does not have this requirement so we do not need to handle that here*/
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(@"Request Complete,recieved %d bytes of data",receivedData.length);
[self.delegate requestReturnedData:receivedData];//send the data to the delegate
}

That wraps up ServiceConnector.m, now lets head over to the ViewController and set up some UI. Set up the storyboard view with 2 buttons(GET and POST) a textview and two text fields, I also added a value1 and value2 label next to the fields to indicate what goes in there. screenshot Drag the controls into the view and connect them to the source file. After taking that screenshot ,I also removed the Lorem Ipsum from the textView because I didn't want it around when the app was run for the first time. For the copy/pasters here is the code for ViewController.h, but remember you are still going to have to create the view and link up all of the controls to the source file.

//
//  ViewController.h
//  Service Reader
//
//  Created by Divan Visagie on 2012/08/25.
//
#import <UIKit/UIKit.h>
#import "ServiceConnector.h"
@interface ViewController : UIViewController <ServiceConnectorDelegate>
@property (weak, nonatomic) IBOutlet UITextView *output;
@property (weak, nonatomic) IBOutlet UITextField *value1TextField;
@property (weak, nonatomic) IBOutlet UITextField *value2TextField;
- (IBAction)getDown:(id)sender;
- (IBAction)postDown:(id)sender;
@end

Finally we move over to ViewController.m , here we set up the button actions which will call the request methods in ServiceConnector:

- (IBAction)getDown:(id)sender { //perform get request
ServiceConnector *serviceConnector = [[ServiceConnector alloc] init];
serviceConnector.delegate = self;
[serviceConnector getTest];
}
- (IBAction)postDown:(id)sender { //perform post request
ServiceConnector *serviceConnector = [[ServiceConnector alloc] init];
serviceConnector.delegate = self;
[serviceConnector postTest];
}

Then we handle the delegate method for when the data is received , here I set the raw string value of the message returned as the text of the textview and set the processed the values of the dictionary keys to the corresponding textFields.

#pragma mark - ServiceConnectorDelegate -
-(void)requestReturnedData:(NSData *)data{ //activated when data is returned
NSDictionary *dictionary = [NSDictionary dictionaryWithJSONData:data];
output.text = dictionary.JSONString; // set the textview to the raw string value of the data recieved
value1TextField.text = [NSString stringWithFormat:@"%d",[[dictionary objectForKey:@"value1"] intValue]];
value2TextField.text = [dictionary objectForKey:@"value2"];
NSLog(@"%@",dictionary);
}

And thats that , the app is complete , now lets run it and see what happens: screenshot First Run screenshot When GET is pressed screenshot When POST is pressed And thats that , it works just as intended. You can download the source including the php script here from GitHub.


Originally posted on Blogspot