Three20 Network Programming ( 1 )

Three20 Network Programming ( 1 )

An easy to follow tutorial for network programming with Three20 framework

Three20 Network Programming ( 1 )

Three20 Network Programming ( 1 )

I have been off “iDevBlogADay” for a while, because I was really busy recently. I am on a project with a much bigger scope than my iPhone games. I have to dedicate as much time as I can. Finally, I am glad I am ready to share something I have learned in my project in past several months.

Actually, I think the title of this blog is a little off. It doesn’t involve anything like socket or TCP/UDP. Be more precisely, it’s a tutorial about how to do web requests by using Three20 framework. My assumption is you already know the basics of the Three20 framework. You can find more details at: http://three20.info. But if you don’t know anything about Three20 yet, don’t be scared. This tutorial actually doesn’t involve much Three20 specific stuff.

No matter you are programming on a iOS game or an application, a common task is to initiate an HTTP request to a web server, and download / upload some information from / to it. It can be done by just using Apple’s iOS framework, but it’s quite tedious. You have to handle all the hairy details of every step. One great alternative is to use “ASIHTTPRequest” — an open source framework created by Ben Copsey. But if you are using Three20 framework in your project already, you don’t have to add this one extra framework. Three20 already provides very solid support to manage web requests.

There are several different kinds of HTTP requests, such as HEAD, OPTION, PUT, … But the most used ones are GET and POST. GET is used for downloading information, and POST can be used to upload information. These two methods will be the focus of this tutorial.

No matter you want to download or upload content, the first thing you need to do is to initiate a web request. To do that in Three20′s world, three classes/protocols are the keys. These classes are: TTURLRequest class, TTURLRequestDelegate protocol, and TTURLResponse protocol. Now let’s look at a really simple example first:

1
2
3
4
5
6
TTURLRequest *request = [TTURLRequest requestWithURL:@"http://www.google.com/robots.txt" delegate:self];
request.httpMethod = @"GET";
request.response = [[[TTURLResponse alloc] init] autorelease];
 
// Send the request
[request send];

You probably can guess from the code, — yes, we are trying to download Google’s “robots.txt” file. To achieve that, we have to create a TTURLRequest object first in line #1, at the same time assign a delegate object; and then in line #3, we created TTURLResponse object to handle the web response.

TTURLRequest

In above example, line #1 shows the most easy way to create a TTURLRequest object, which is responsible for constructing an HTTP request based on parameters you passed in, sending the request to the web server, and then handle the control to the TTURLResponse object. A few things that need your attention in this process:

  • Send request: there are two ways to send out a request: asynchronous or synchronous. By default, when you call [request send], the request will be sent out asynchronously. Or you can use [request sendSynchronously] to make the call blocking.
  • Time out: this is a really important parameter but usually got ignored. The default time out for a TTURLRequest is 5 mins, which is quite long. You can change the time out like this:

    request.timeoutInterval = 15.0f; // in seconds

    Remember to use the latest Three20 framework. In earlier versions this property was not there.

  • Max download size: by default, Three20 has an arbitrary limit for the size of data you can download for each request: 150k. If you are going to download more data in the request, the limit can be removed by calling:

    [[TTURLRequestQueue mainQueue] setMaxContentLength:0];

    Personally I think it’s always a good idea to remove the limit (or set it to a much higher value), ’cause 150K is really nothing on today’s Internet. For now, don’t worry about the TTURLRequestQueue class. We’ll come back to it in the second part of the tutorial.
  • Reporting progress: TTURLRequest class provides several convenient properties for the caller object to monitor the progress of the request, which are:
    • totalBytesDownloaded
    • totalBytesExpected
    • totalBytesLoaded (if this request is for uploading content)
    • isLoading: whether or not the current request is activeWith the help of these properties, you can easily create a download progress bar in the delegate callback method. We will revisit this later in next section.
  • HTTP headers: HTTP headers are essentially key value pairs. For example, when you have multiple async HTTP calls at the same time, it’s hard to tell which one comes back first. In this case, you can use the “ETag” HTTP header to identify each of them:

    [request.headers setObject:@"firstRequest" forKey:@"ETag"];

    And then in the delegate callback, you just need to check the “ETag” header to identify each request. Please note that Three20 API already extracted some commonly used HTTP headers into properties, such as “contentType”. So before you set the header value, make sure to check if it’s already part of the request’s properties.
  • HTTP method: In our example above, the HTTP method is set in line #2. The most used two HTTP methods are GET and POST. Usually GET is for downloading, and POST is for uploading.
  • Last but not least, remember to encode your parameters before you create the TTURLRequest object. For example, if your URL is “http://www.google.com/search?q=apple’s latest ipad”, it needs to be encoded into: “https://www.google.com/search?q=apple’s%20latest%20ipad”. For how to encode/decode an URL, please check out this post on stackoverflow.com.

TTURLRequestDelegate

The delegate object is the place to implement some real business logics. All methods defined in this protocol is optional, but usually you want to implement at least two methods:

- (void)requestDidFinishLoad:(TTURLRequest*)request — this delegate method is called when the request has finished successfully.
- (void)request:(TTURLRequest*)request didFailLoadWithError:(NSError*)error — this one is called the request has failed. An error message is sent back along with the original TTURLRequest object.

TTURLRequestDelegate is a very important protocol in Three20 framework. You can see it in almost all web request related classes. For example, TTImageView, a view to display image in Three20′s flavor, also implemented the TTURLRequestDelegate. That’s because TTImageView is capable of displaying an image by downloading it from web directly. So it has to implement the TTURLRequestDelegate to handle the HTTP request.

Besides above two methods, other methods also provide some useful information. For example, in previous section we mentioned using TTURLRequest's several properties to monitor the progress of the request. That can be done in the delegate method requestDidUploadData:

1
2
3
4
- (void)requestDidUploadData:(TTURLRequest *)request {
float progress = request.totalBytesLoaded / (float)request.totalBytesExpected;
NSLog(@"Current progress: %f", progress);
}

TTURLResponse

TTURLResponse is the last pice of the puzzle of Three20 network programming. It is actually a protocol with two methods defined:

- (NSError *)request:(TTURLRequest *)request processResponse:(NSHTTPURLResponse *)response data:(id)data
- (NSError *)request:(TTURLRequest *)request processErrorResponse:(NSHTTPURLResponse *)response data:(id)data

The first one is for processing response data from a successful request, and the second one is for a failed request. You can implement your own TTURLResponse instance to handle the response, but in most cases, the provided four classes in Three20 framework should be sufficient.

  • TTURLDataResponse: This is the most straightforward one. If you look at the source code of this class, it just simply save the data from the response to its internal readonly property “data”, and then you can use the data to do whatever you want. For example, you can convert the data to a NSString:

    NSString* str = [[NSString alloc] initWithData:response.data encoding:NSUTF8StringEncoding];

  • TTURLImageResponse: TTURLImageResponse is similar to the TTURLDataResponse. The only extra work it does is trying to convert the data to an UIImage object, and save it to the internal readonly property “image”. This class is used especially less often because the TTImageView class also provides the same functionality to download images from web, and is more capsulated comparing to the TTURLImageResponse class.
  • TTURLJSONResponse and TTURLXMLResponse: I am going to talk about these two classes together because they are really similar to each other. Both are often used for API calls; both handle data in tree structures and have a root object; both already have a parser built-in. In the implementation of - (NSError *)request:(TTURLRequest *)request processResponse:(NSHTTPURLResponse *)response data:(id)data, the built-in parser will try to parse the data into a root object. Depending on the structure of the JSON/XML, it could be a NSArray, or a NSDictionary. So you need to a test it before you start processing the parsing result, something like:

    TTDASSERT([response.rootObject isKindOfClass:[NSDictionary class]]);

    Another caveat is how to convert your object to JSON string so that it can be sent through an HTTP request. The JSON framework used in Three20 is SBJSON. It already knows how to convert a collection to a JSON string. But to convert your own class to a JSON string, you have to implement the “- (id) proxyForJson” method. This method must return a type that SBJSON already knows how to handle — for example, most of the cases you can just convert your object to a NSDictionary. Or you can also just return a NSString if you like.

So far we have covered most of the basic stuff in Three20 network programming. You should have a good idea about how to work with HTTP GET method now. Since one of Three20′s biggest problems is lack of documentation, I hope this tutorial can make this part easier for you. Before I finish this post, do you mind doing a homework? ;-) I always believe you will learn more when you actually get your hands dirty. The task is simple:

use Three20 framework to download the content from this URL:

http://www.flickr.com/services/rest/?method=flickr.test.echo&format=json&api_key=0aaaec5a4450a7db6a939e38bf768eed

and then parse the response into a NSDictionary.

In the next post, I’ll talk about more advanced network programming such as uploading a big file, and some neat tricks. Stay tuned.

References

 
Add a comment

Comments (2)

  1. kokomo, October 16, 2012
    thank you~ it was a excellent tutorial to me :) Reply
  2. Kenneth, June 15, 2012
    I agree the title is a little off. Please fix it. Good article nevertheless. Reply

Add a comment

Top
(it will not be shared)