Archive for December 2010

A common pattern in iPhone applications that load data remotely in a table is to utilize a button at the bottom of the table with a “Load More” label.  Typically, when you click on the Load More button, a request is made to the server to download additional items.  This form of lazy loading enhances the user experience and improves application performance.

I knew Three20 handled this scenario but I couldn’t find a good example that walked through each component that was required to implement it.  It was a challenge to get all the bits to work together so here is my breakdown in case others are facing a similar challenge. I’m going to divide the post into two parts. In part 1 we’ll just hook up the classes with each other then in part 2 we’ll implement the actual request / response logic.

If you’re not familiar with the Three20 library, I highly recommend you take a look at it for your iPhone / iPad projects. For this example, I’ll assume you have integrated Three20 into your project already and are somewhat familiar with the library.

To demonstrate the load more feature we’ll be doing a simple integration to display my public Twitter timeline with paging. Since my timeline doesn’t require authentication, we won’t have to get bogged down with implementing the OAuth protocol. Now, let’s look at the players:

TTTableViewController

To start, let’s add a subclass of the TTTableViewController. This will just provide us with a base controller with a table view to utilize for demonstration purposes. In addition, we’re going to stub in a class which will serve as the datasource for this controller.

MBTwitterController

Subclass of TTTableViewController

That’s pretty much all you have to do within the tableviewcontroller thanks to Three20 encapsulating a lot of the delegate logic into the datasource object. Now, let’s create the datasource for the table.

TTListDataSource

If you’ve worked with Three20 and table implementations, you’re probably familiar with this class. Again, we’ll subclass it to create a new datasource object which will be consumed by our table view controller.  We’ll also add some code which will work with the TTURLRequestModel.

Subclass of TTListDataSource

A few things are going on in this class. First, we allocate the TTURLRequestModel which we’ll add in just a minute. We also implement the model method which we’ll set to the TTURLRequestModel above. This is very important if you want to keep your sanity trying to debug later on. Below is the header file for the class.

MBTwitterDataSource.h

@interface MBTwitterDataSource : TTListDataSource {
	  MBTwitterRequestModel* _twitterFeedModel;
}
@end

TTURLRequestModel

The last class we’re going to create will be a subclass of the TTURLRequestModel. This class will encapsulate all the network operations to interact with the Twitter API.

MBTwitterRequestModel

@interface MBTwitterRequestModel : TTURLRequestModel {
}
@end

These are all the classes involved in getting this to work. In the next part, we’ll look at writing the code to interact with the Twitter API and how to actually add the “Load More” button to the table cells.

One of the most popular formats for writing agile user stories follows this template:

As a [role], I want to [feature] so that [goal]

Many organizations translate this into a spreadsheet where each column represents a different field the story writer can fill in:

I have used this template on almost every agile project I have participated in.  For the most part, it works very well. It typically provides a great launch point for additional discussions before it makes it into a sprint.

One of the most common mistakes I see when introducing the template (and agile stories in general) to a new team is a tendency to define every role as just a generic “user”. For example, I’ve seen user stories as generic as:

“As a user, I want to upload photos to a library so that I can use them on a post”

Although its syntactically correct, it is vital that we define a role and not a “seat” on the system. A more valuable user story would look like this:

“As a user designer content author, I want to upload photos to a library so that I can use them on a post”

Notice how this story now has a better context of who will be using the feature and how. This could provide valuable insight into the intended audience and how best to implement the feature — a designer may imply more advanced features while a content author would use the image as is.

Always avoid the generic “user” role in your user stories.

Hope this helps.

These kinds of projects are surely a sign of things to come. More and more executives are realizing the value of social media as a robust, scalable and (relatively) inexpensive channel for marketing their brands and generating demand for their products.

I’ve always been a fan of how Twitter organized their API.  Particulary, I enjoyed being able to change the format of the response by just changing the extension of the URL from JSON to XML.  A typical Twitter API call looks like this:

http://api.twitter.com/version/statuses/public_timeline.format

So while this public timeline call will return XML:
http://api.twitter.com/1/statuses/public_timeline.xml

This one would return JSON:
http://api.twitter.com/1/statuses/public_timeline.json

The proper REST way to do this is by changing the headers in your request to ask for a particular file format.  Indeed, an implementation utilizing request headers has already been written.  However, I prefer Twitter’s implementation which coincidentally seems to be a feature of the Scala / Lift framework.  To accomplish this with ASP.NET MVC, we are going to build an attribute that checks the incoming request and then attempts to render the resulting model in the selected format.

First, some words of caution.  I don’t think this method will scale if your API / web application takes off.  Although it is a great example of the DRY (don’t repeat yourself), code-once software development practice, it does somewhat tightly couple your API to your front end.  Twitter faced a similar situation when their API was hosted on the same domain as the web application.  Eventually, Twitter moved the API to api.twitter.com.  This practice allows the API to evolve independently of the front-end of your application.  With that warning in mind, let’s dive into the code.

They way we’ll implement this functionaly is to develop a custom action attribute which will check for a “format” parameter on each request to decide whether to return the model as a JSON, XML or the default view that the controller will return. This is slightly different from Twitter’s implementation but it simplifies some of the routing issues we would have with ASP.NET MVC.  Using an API-driven development approach, I’ll start with an existing controller and add a (non-existent).  This gives me an idea of how it would work.

I could add some additional parameters at this point to restrict which formats to accept, but we’ll leave that out for now (KISS – Keep It Simple Stupid!).  Next we’ll just generate the class using the smart tag in Visual Studio which will create the stub for it.  We want this action filter to execute before the response is returned to the client but after the data model has been populated.  This implies we’ll be overriding the OnActionExecuted method:

At this point, everything should build.  Our next step is to create two custom ActionResult subclasses which will return either Xml or Json representations of the model you pass in.

ASP.NET MVC includes a JsonResult which we’ll use for the JSON format.  Although there is no XML equivalent, the MVCContrib library does have an XmlResult class.  You can download the bits here to provide the XmlResult class (along with some other very useful features).  Add the assembly as a reference to your project.

Now we have the two ActionResult’s we need to implement the solution.  Below is a screenshot of the finished method.  Essentially, we’re looking into the filter context to find the file extension.  Depending on if it’s json or xml, we use a different action result serialization technique.

Notice that we need to set the JsonRequestBehavior in order for this to work.  There are several security vulnerabilities which you should explore before defaulting this behavior at such a broad level. Phil Haack details some of the issues with JSON Hijacking here.

That’s all there is to it.  Hope this helps!