In my previous
TechRepublic series, we used an existing web service to create an iOS app (“Creating
a web service, parts one and two“). In this series, we’ll create the web service backend for a different
app called iGlobe, which is a game I created a while ago.

Basically, we want the user to be able to tag a place or a
person and get points for that action. (The competitor with the most points at the end of the game wins a money
pot.) In order to do this, the app has to interact with a web service, which
we’ll create. Our web service will need to be able to:

  • Store each player’s username information
  • Receive users’ points
  • Present users’ points

In this iOS 6/7 tutorial we’ll use a helper class called
SantiappsHelper, which contains the code to run these connections to the web. A
standalone class in such cases is usually called a library, which takes care of
those processes. If you only require one instance of such a class (like in our
case), you create a Singleton pattern. You only want one instance of the
connection, because you don’t want many instances of the connection class
creating, receiving, and disconnecting — that could end up in multiple
connections to the same resource at different times, which could confuse you or
the server.

Here’s what we’ll cover in this series:

1. Create the web database

2. Create the web service
backend

3. Create iOS frontend
(Storyboard)

4. Fetch data

  • a.  NSURLConnection
  • b.  GCD and completion blocks

5. Exchange data between devices using iOS 7’s Multipeer Connectivity Framework

Step 1: Create the web database

Web services are usually large databases of information; our
database will need a table to store all the information we mentioned above. We
interact with databases in four main ways: Create, Read, Update, and Delete (CRUD)
data. So let’s take a short detour and talk about databases — specifically,
their structure and how we interact with them.

Databases

Databases are information stores, which can be written as
files (such as Word or PowerPoint). The information in such files has a
predetermined structure that Word and PowerPoint know how to read and access in
order to present what you want and let you edit it and store it again; the
problem is only Word will read a docx file, and only PowerPoint will read a
pptx file. The great advantages of databases are they store information in a
very compact way and can be read by many different interfaces. The simpler the
database, the more interfaces can read it.

We’ll use a database that is usually available for free in
most web hosting services. My web hosting service has phpMySQL, which comes
included with a free package. If you want other databases such as MSSQL, you need a paid service. Figure A is what my database management
interface looks like.

Figure A

 

See an enlarged view of Figure A.

We have a database named iglobe on localhost with two
tables: users and tags. The users table (Figure
B
) contains a primary key with a username, a password, a password hint, a first
and last name, as well as an email, a phone number, an address, and such
regular stuff.

Figure B

 

See an enlarged view of Figure B.

The tags table (Figure
C
) also has its own primary key (tagID), the corresponding username, an identifier,
the tag’s latitude and longitude, the date it was created, and how many points
it’s worth to that user. There is also a country field, which was implemented
later as the project progressed (it’s been in the works since 2011).

Figure C

 

See an enlarged view of Figure C.

Step 2: Create the web service backend

The idea for our web service will be to read from these
tables and write to them whatever data users request or post to them. This part
requires you to know some PHP. Let’s start by
looking at what the code to read a table looks like.

<?php

include_once("JSON.php");
$json = new Services_JSON();

$link = mysql_pconnect("localhost", "user", "pass") or die("Could not connect");
mysql_select_db("iglobe") or die("Could not select database");

$arr = array();

$rs = mysql_query("SELECT * FROM users");
while($obj = mysql_fetch_object($rs)) {
$arr[] = $obj;
}

Echo $json->encode($arr);

?>

First, we include the JSON.php file in order to access JSON files on your server (make sure your webserver or host provides you with at least PHP 5.2). Then, we make a connection to the database using the database user and password as well as the database host. Now we create an array object so once we execute the mysql_query where all entries from the users table are collected into $rs, we can put that object into our $arr[] object. Finally, we encode the $arr into $json and echo it onto the screen.

Once this code is up and ready along with your database (including some records), you can direct your browser to this file (which I called myserver.com/getusers.php). I get the following result:

[{"id":"35","username":"zlitsami ","password":"932d1c42a4e4880e57037994fd3584b1","password_hint":"","lastname":"","firstname":"","email":"joe@iglobe.com","phone":"","address1":"","address2":"","city":"","state":"","zip":"","country":"","url":"","permissions":"1","udid":"9","userCreated":"2013-01-01 14:27:22","time_queued":null,"time_sent":null}, {another}, {another}]

This is an array that has many elements in it. Each element is a user’s
table entry. Each entry is a dictionary of key value pairs. Look familiar?

Now that we know how to read information from our database, let’s create
the code for writing to the database.

<?php
$con = mysql_connect("localhost","user","pass");
if (!$con)
{
die(‘Could not connect: ‘ . mysql_error());
}

mysql_select_db("iglobe", $con);

$sql="INSERT INTO tags (username, latitude, longitude, country,destintyudid,points) VALUES (‘$_POST[sender]’,’$_POST[latitude]’,’$_POST[longitude]’,’$_POST[country]’,’$_POST[receiver]’,’$_POST[points]’)";

if (!mysql_query($sql,$con))
{
die(‘Error: ‘ . mysql_error());
}

echo "1 record added to tags";

mysql_close($con)
?>

We connect to our database again, and we create a sql
statement with values to insert (these values come from a form that was either
online or on a mobile device).  We
execute that sql statement with our connection and echo the results for
verification to the user. I called this file writephp.php.

Before we move onto iOS, let’s test our service online. Create
an HTML file called Writeform.html and save this code to it:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<form action="writephp.php" method="post">
<table style="text-align: left; width: 100%;" border="0"
cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td>Name:</td>
<td><input name="sender" type="text"></td>
<td></td>
</tr>
<tr>
<td>UDID(unnecessary):</td>
<td><input name="udid" type="text"></td>
<td></td>
</tr>
<tr>
<td>Latitude:</td>
<td><input name="latitude" type="text"></td>
<td></td>
</tr>
<tr>
<td>Longitude:</td>
<td><input name="longitude" type="text"></td>
<td></td>
</tr>
<tr>
<td>Country</td>
<td><input name="country" type="text"></td>
<td></td>
</tr>
<tr>
<td>Receiver</td>
<td><input name="receiver" type="text"></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td><input type="submit"></td>
</tr>
</tbody>
</table>
&nbsp;&nbsp;&nbsp;&nbsp;<br>
</form>
</body>
</html>

Now load the form on your web browser and submit data to
your database.

I don’t want to make this web service too complicated
because I want to keep your attention on the iOS side, so let’s create a form
to eventually read points from our web service for a particular user. Create
another HTML file called Testform.html and save this code to it:

<HTML>
<head>

<form action="readpoints.php" method="post">
User: <input type="text" name="userNa"/>
<input type="submit" />

</form>
</head>
</HTML>

And create its php counterpart:

<?php

include_once("JSON.php");
$json = new Services_JSON();

$link = mysql_pconnect("localhost", "user", "pass") or die("Could not connect");
mysql_select_db("iglobe") or die("Could not select database");

$username = $_POST["userNa"];

$result = mysql_query("SELECT username, SUM(points) AS PUNTOS FROM tags WHERE username=’$username’ GROUP BY username");
// THIS RETURNS ARRAY NOT READ PROPERLY BY iOS JSON
$resultado = array();
while($obj = mysql_fetch_object($result)) {
$resultado[] = $obj;
}
Echo $json->encode($resultado);

?>

We’ll use this last bit of code later once we get more data
into the database.

So far, we have a resource that returns the points for a
particular user, readpoints.php; this is what’s called a web service endpoint.
Web services can have many endpoints. In a game or an app, we might want to get
a lot of users’ points at once to fill up a leader board, for example. We might
want to fetch a lot of transactions from an invoice database instead of one by
one. So let’s get ahead of ourselves and create an endpoint to manage a set of
input data. In our case, we must be able to pass the web service a set of
users. Our file would look something like this:

<?php

include_once("JSON.php");
$json = new Services_JSON();

//1. PROCESS RECEIVED ARRAY
$handle = fopen("php://input", "rb");
$http_raw_post_data = ”;
while (!feof($handle)) {
$http_raw_post_data .= fread($handle, 8192);
}
fclose($handle);

//1.1 Just decode to see what kind of object it is
$post_data = json_decode($http_raw_post_data,true);

if (is_array($post_data))
$response = array("status" => "ok", "code" => 0, "original request" => $post_data);
else
$response = array("status" => "error", "code" => -1, "original_request" => $post_data);

//2. CALL DB QUERY
$link = mysql_pconnect("localhost", "username", "password") or die("Could not connect");
mysql_select_db("iglobe") or die("Could not select database");

//3. CREATE FINAL ARRAY TO RETURN
$arrayToReturn = array();

//4. CYCLE THROUGH USERS
foreach ($post_data as $value)
{
//CREATE QUERY
$result = mysql_query("SELECT username, SUM(points) AS PUNTOS FROM tags WHERE username=’$value’ GROUP BY username");

//EXECUTE QUERY & ADD EACH USER/POINTS DICTIONARY TO $resultado ARRAY
$resultado = array();
while($obj = mysql_fetch_object($result)){
$arrayToReturn[] = $obj;
}
}
Echo $json->encode($arrayToReturn);
?>

This basic php code takes the passed in array as we
mentioned and loops through the database to get the points for each user. This
is important because we save the app a lot of trips to the web server database.

Step 3: Create iOS frontend (Storyboard)

We’ll now work on our iOS Storyboard or frontend. Then we’ll
hardcode data and fetch web from the actual backend; this way, we can see what
our frontend will require in terms of data models, and then we can fetch web
data and replace our data in those data models. We’ll also be learning two ways
of fetching data: inline, messy code and neat and tidy coding.

Follow these steps:

  1. Create a new Empty project using Storyboards, ARC,
    iPhone, and NO Core Data.
  2. Go to the storyboard and drag a UITableViewController
    onto the grid.
  3. Create a class called UsersListViewController. In
    Storyboard, select the scene and in the Identity Inspector make our scene
    UsersListViewController type from the dropdown list.
  4. Run a quick test to make sure our tvc is
    working.
  5. Build & Run. You should get an empty
    tableview.

Let’s review what we’ll do in this section:

  • Add an array property to your .m file
  • Prefill that array in viewDidLoad
  • Eliminate the pesky warning lines
  • Make tableview return one section
  • Make tableview return array count
  • Make tableview cell return array objects

This should be second nature to you by now, so I’ll blaze
through the specifics.

Here’s the property code:

@property (nonatomic, strong) NSArray *testArray;

Here’s the viewDidLoad code:

– (void)viewDidLoad
{
[super viewDidLoad];

self.testArray = [[NSArray alloc] initWithObjects:@"me", @"you", @"them", nil];
NSLog(@"array %d", [self.testArray count]);
}

Here’s the return array count code:

return [self.testArray count];

Here’s the cFRAIP code:

– (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

// Configure the cell…
cell.textLabel.text = [self.testArray objectAtIndex:indexPath.row];
return cell;
}

Before you Build & Run, select the UITableViewCell in
Storyboard and, in the Attributes Inspector, make sure you use Cell as the
Reuse Identifier. Your app should work fine.

If you Build & Run now, users should be displayed in the
tableview. Cool!  That’s what we’re
going to want to do — that is, display a list of users in a tableview and then
add in the points, like a score table.

Figure D is a mockup
of what our app will look like. In essence, we’ll have a tab bar controller
manage three views: Users, Map, and Instructions. We’ll also throw in a Login
view as the app launches. This should give you an idea of what kinds of tasks
we’ll need to perform in order to accomplish this.

a)
Present a login view controller

b)
Save user and pass information

c)
Fetch user data from the web service

d)
Plot points on a map

e)
Display instructions in a view

Figure D

 

See an enlarged view of Figure D.

You should be able to re-create this in your Storyboard. Here
are the basic steps:

1. Select your existing UsersViewController scene
and, from the Editor menu, select Embed In | Tab Bar Controller. You should have
a scene and a class for UsersViewController, and the scene should be set to its
Class Type in the Identity Inspector.

2. Clear out the second scene that was added when
you embedded your tableview scene in a tab bar (by clear out, I mean make sure
it doesn’t have any labels or other controls in it). Now drag a UIMapView into
it. Add a UINavigationBar to the top and two buttons (Plot and Bump) on either
side. Create a MapViewController class for it and set its type. Add a MKMapView
IBOutlet property and two UIBarButtonItem IBOutlet properties and connect them.
Add the MKMapViewDelegate.

3. For the last view add another UIViewController and
drag a UIWebView and a UINavigationBar into it. Create its class file and name
it InstructionsVC. Add a UIWebView IBOutlet property and connect it. Add the UIWebViewDelegate
and don’t forget to set its scene type.

4. Add a UIViewController, call it
ModalViewController (Figure E is
what mine looks like), and create all of the IBOutlet properties for it —
that’s four labels with static text (User, Pass, Email, and Pass Requires…). There
are three UITextFields with placeholder text to guide the user. There are three
UIButtons for different actions. The person icon is a button with a Background
Image set to the image; it will be the button the users will use to upload
their image to the web server.

Other class files we could create now are TagListController,
Tag/Users Model, and Annotation/PlacemarkVC.

Figure E

 

See an enlarged view of Figure E.

Take a couple of minutes to visualize what the app layout
will look like now that we have a better idea of where we’re headed, and then
compare your visualization to the initial sketch you made of your app.

In part two, we’ll connect to the web service and fetch actual data.