views:

149

answers:

2

Hi,

Imagine a table view listing some recipes. Each time the user taps on a recipe a new table view is loaded listing receipe ingredients.

To get the information, I'm asynchronous calling a REST API using:

NSURLRequest *request = [NSURLRequest requestWithURL:url
                                      cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
                                      timeoutInterval:30];

When user taps on a recipe, a call to the API is made to get recipe ingredients. However, once in the new view (which list ingredients) and before the answer is received, the user can go back and select a new recipe.

In this case, I'll recive two answer; one for each request. The problem is I don't know to what request is this answer for and I'll refresh UI with a wrong content from a wrong answer.

I'm not sure which is the right approach in this case. I'm thinking about including in the answer each request parameter. So, if I'm, for example, using the API to search for certain term, we say "foo", I'll include the term in the answer too, for example:

Request:

http://domain.com/api/search?term=foo

Answer

{
"requestType": "search",
"term": "foo",
"result" : "a foo result"
}

It looks strange to me to include each request parameter on each answer, but it is the only solution I found to create a stateless API ready to be called asynchronous.

¿Is there any other way of accomplishing this?

(I'm using a delegate pattern assigning an object to each request which is called when the answer is received. The problem is, in the example of recipes, that the ingredients table view is reused eache time recipe ingredientes are listed).

+1  A: 

One possibility is to include a unique "request ID" in the request, and for the server to echo it. Then the server doesn't need to return all the request parameters, just the request ID. The client would generate a new ID for each request, possibly using something as simple as incrementing an integer.

Another possibility is to create a "cancelable asynchronous request". When you issue the request, return an object that can be used to cancel the request. If the request is cancelled before the delegate is fired, then ensure that the delegate won't be fired. When a response comes back for a canceled request, just throw it away. For your ingredients table, before you issue a new request, you cancel any pending request (so that you have at most one uncancelled request at a time).

One way to implement this is to build a two-stage callback. The first callback, which is managed by the infrastructure, just checks to see if the request was cancelled. If not, it goes on to call the second callback (which is actually your delegate).

Daniel Yankowsky
A: 

A typical approach here is to assign a single unique value (a "key" value) to each recipe and send it back on the response, much like you proposed. The key value could be the recipe name if it is unique and short, but the more common strategy is to just use a unique number or another value that is meaningless to the user, but serves to uniquely identify a recipe over time even if (for example) the name changes. In database jargon, this is the difference between a business key and a surrogate key. Both are unique identifiers, but the business key has meaning to a user (e.g. a name) whereas a surrogate key doesn't. My recommendation is to use a surrogate key because you can make it short and it will never need to change because the user doesn't care about it.

Note that if you accept a key back as a parameter in any of your web service calls, you must validate it (or encrypt it if security is a concern), since you never know if the client will tamper with it.

By the way, I'm making an assumption here that the client "knows" which recipe was selected most recently, so it can ignore responses for other recipes.

Rob H