Okay, we are going to begin to get into web services in an
iOS environment. Most apps now use data from the web. Whether that data comes
from a private (business back end) or public (weather services) source, most
apps use it.

So for this app we will take baby steps towards reading data
off the web and parsing it (a fancy name for converting it to our iOS side)
into usable iOS data for our app. Then we will worry about what to do with our
data inside our app.

Getting started

We have already experienced this with our Twitter
app, but we will make it a bit more useful this time - as well as
entertaining. With great power comes great responsibility, so this means you
will have to delve into a bit of server programming. It will not be too complicated
I promise, but it will be very enlightening. Thus one of the requisites for
this tutorial is that you have access to some public web server (or you could use a webserver for mac such
as MAMP, which you can download.

MOCK DATA - Example Free Web Service Flickr

I have a website setup where you can read data for testing
purposes. In your web browser go to:

This displays a json response. It's a little atypical
because it has a leading string in there, but the rest (beginning with the
first "(") is typical. Ok so let's try to fetch this data from within
our app. Create a new Single View Project with ARC and Storyboards and call it
TRWebService.

Select the Class Files for ViewController and click Delete. When
you are prompted to answer this question click on Move To Trash (Figure A).

Figure A

Go ahead and click on Move To Trash.

When you select Remove References you are basically just removing
the existing XCode references to those files, but the files are still there. So
if you think you may need files later, just maybe not for this particular
project, then Remove References and you can later move the actual files from
the TRWebService XCode project folder to some other folder. If you are positive
you will never use a file again, go ahead and Move To Trash.

Now let's add a New File and make it a tableview controller
(Figure B)

Figure B

I did this for two reasons; first, it shows how to remove
files and add files. Second, because this way we have XCode prepare a
UITableViewController for us which gives us those boilerplate methods that come
with all UITVCs instead of having to remember what they are called or how they
are coded. As to why I chose UITVC, I guess I just like scrolling cells!

UITVCs are nice because they come with some methods, which
we can use to explore the viewcontroller lifecycle. Let's look at some of these
methods now:

-initWithStyle:
This method is used to add a particular styling to tableviews. If we build and
run the app now we get this CRASH hahaha! I forgot to replace the scene in
storyboard. But I decided to leave the crash in the tutorial; it's a good way
to get used to them, because they are great for learning. Let's analyze the
error shall we:

'NSInternalInconsistencyException',
reason: '-[UITableViewController loadView] loaded the "2-view-3" nib
but didn't get a UITableView.'

XCode is telling us that UITableViewController's loadView
method tried to load a tableview from the nib, but didn't get one. Of course,
it didn't. There isn't one! Our app came with a storyboard which included a
UIViewController scene, not a UITVC one. So let's erase the UIViewController
scene from storyboard. Select the scene until there is a blue rectangle around
it and simply delete it. Now drag a UITVC from the Object Library onto the
storyboard. Don't forget to set its Class Type in the Identity Inspector to
ViewController. Now let's run the app again. Great! Now we get Figure C.

Figure C

So in this method you can modify some style settings. It
gets called only once, at the very beginning of the viewcontroller's life. Other
such methods which get called only once and at the very beginning are:
initWithCoder, initWithFrame and viewDidLoad.

-viewDidLoad is a method
that you will see quite a lot because it is used as a starting point for
many other tasks. After all, once the view has loaded, the user can begin
to see things on the screen.

-viewWillAppear, as well
as its other closely related cousins, viewDidAppear, viewWillDisappear are
methods which are called every time the view will do this or that. The
difference is that views can appear many times but they are only loaded
once. So for example, if you want the view to be refreshed each time the
user loads an app running in the background, or switches tabs within a
UITabBarController etc., you want to use the methods call every time the
view appears. If you refresh data inside viewDidLoad, of the other
previous methods such as initWithStyle/Coder/Frame/NibName, the data will
only be refreshed once!

-nOSIT, nORIS, cFRAIP and
dSRAIP are tableview methods and I use those abbreviations to refer to
them. They are not standard acronyms so be prepared for people to go "HUH!?".
numberOfSectionsInTableView, numberOfRowsInSection, cellForRowAtIndexPath
and didSelectRowAtIndexPath are for the most part, required methods in a
tableview. nORIS and nOSIT get called only once but cFRAIP gets called
many times, each time new cells appear in view for whatever reason,
scrolling, loading of the view, deletion, editing etc.

Okay, enough about boilerplate methods of UITVC. Other VCs
have different methods based upon what they do and which protocols they conform
to.

Get some data

So now we want to get some data off the web before we put it
into our iOS app. We do this in three steps; create a URL, create a URLRequest
and finally make a URLConnection. Since these are all Mac methods they are
called NSURL, NSURLRequest and NSURLConnection. Our code will look something like this:

Now the way this works is that it creates a connection which
fetches and returns a response and some data if the response is positive. NSURLConnection
sets the current view controller as its delegate so this viewcontroller must
implement the delegate methods that will receive the response and the data.

I just want to review the concept about not blocking the
main thread. This is so important because what happens is that we want to have
all of our data fetched by the time the user interacts with out viewcontrollers.
So you would be tempted to go as far back as the AppDelegate's
applicationDidFinishLaunchingWithOptions method to put this code and the
respective delegate methods. We can do this for this example because the
response and data is returned so quickly that it doesn't pose a problem. But
what if the Internet connection was missing or slow?

So let's move it to our ViewController. Go ahead and make
your viewDidLoad method look like this:

Now don't flip just yet. They look intimidating but they're
quite easy to understand.

If we receive a response then the method didReceiveResponse
is called and we can do something with that response. Have you ever seen the
infamous HTTP 404 error codes when loading a page that no longer exists? Well,
HTTP is a protocol much like any other and as such, when a resource is not
found, it displays a standardized response, called response code, which is #404.
We can get the code responded by the Flickr server as well as the return file
type and log them in our console.

If the response received is good, which by the way is known
as an HTTP 200 code, the server begins to send data. That data is received in
the didReceiveData method. If there is an error in the connection then the
didFailWithError method is called. You can test this one out by turning off
your Internet connection and running the app. You will see the actual error
returned by the Flickr server.

Finally, once all the data from the connection has been
received, the connectionDidFinishLoading method is called and we can manipulate
our data. So before we get to playing with data, let's go ahead and run the app.
Look in the console and you should get something like this:

As you can see there is our response code and our file type.
Now let's try to take this data and put it into an iOS object we can use. We
know the type returned is text, so we might be tempted to put this data into a
string. To do this we will change the didReceiveData method to this:

This means it is now an NSDictionary and we can use the data
in our app. Not so painful after all!

Ok so let's first make our flickrDictionary into an ivar
instead of a local variable of the didReceiveData method. Add it to the interface
in the ViewController.m file, up top. Go ahead and add a mutable array as well
so we can parse the dictionary and put the objects into the array for use in
the tableview.

Now look carefully at what we have. It's a dictionary of
dictionaries. The first dictionary entry is "api_key", whose value is
set to a "_content" dictionary. The second entry is "format"
whose key is also a "_content" dictionary, so on and so forth. What
we want to do is take the _content value of each and put it into our array so
we can use the array to populate our cells. Since we want to parse the dictionary
only once it is fully populated from the web fetch, let's change our
connectionDidFinishLoading method to this:

So we declare that our cFRAIPArray will contain five objects.
We then loop through all its keys and put them into an id object. Now we have
to test if those objects are dictionaries (as the first four are) or else, like
the last entry, which is just a string. In the case the object IS an
NSDictionary grab the value for the key called "_content" and add it
to our cFRAIPArray. Finally we reload the tableview.

Pay close attention to the subtle difference between each
if/else code branch. In the first, we test if flickrDictionary's key is a
dictionary, and if it is, we put THAT key into a new dictionary called "object".
We then get the value for the "_content" key of the OBJECT dictionary
(NOT of the flickrDictionary) and add it to the cFRAIPArray. Then in the last
entry, we simply take the flickDictionary key and add it to the cFRAIPArray.

Then in our cFRAIP method we simply say:

cell.textLabel.text = [cFRAIPArray objectAtIndex:indexPath.row];

Now Build & Run and you have a perfectly populated
tableview. (Figure D)

Figure D

Third Party

Well that wasn't so hard! There is a lot you can do with third-party
APIs such as Flickr, Twitter and others. Some services such as Twitter even
have a developer console you can access directly from your Twitter app. Simply
open up the Twitter app on your Mac and go to Twitter | Preferences | Developer
and check the Show Developer Menu.

Now from the Develop menu, which is added to the menu bar,
select the only option, the Console option. You should get the window shown in Figure E.

Figure E

You can play around with these. Some you can use as
Anonymous but others you would need to authenticate for.

Another option is to use web services such as Parse.com,
which allow you to update data in many formats and then request that data via
their custom calls. This is very convenient since you don't need to worry about
taking care of servers and uptime etc.

Yet another option is to create your own web service. This
of course is the most complicated option, but you can make it as complex or
simple as you wish. This is also the most flexible option. In the next part we
will roll our own web service, so stay tuned.

About Marcio Valenzuela

My name is Marcio Valenzuela and I am from Honduras. I have been coding in iOS for 5 years and I previously worked on web applications in ASP and PHP/mySQL. I have a few apps up in the app store and am currently working on a couple of Cocos2d games...

Full Bio

My name is Marcio Valenzuela and I am from Honduras. I have been coding in iOS for 5 years and I previously worked on web applications in ASP and PHP/mySQL. I have a few apps up in the app store and am currently working on a couple of Cocos2d games at Santiapps.com. I have a BS in Biochemistry, Masters in Business Administration and yet being a father has me stumped :). I've lived in Tampa, Paul Smith, D.C., Savannah and currently San Pedro Sula. I've visited Canada, France, Spain, U.K., China, Hong Kong and Mexico. As you can see I love cultural diversity as well as learning about a wide variety of subjects.