Using TTNavigationCentre and TTListDataSource

0 views
Skip to first unread message

Weyert de Boer

unread,
Jun 8, 2009, 8:38:19 PM6/8/09
to Three20
Hello,

I am currently working on a iPhone application where I am using remote
calls to obtain the data which needs to be displayed in the table
views. Now this part works nicely with the TTListDataSource and
TTURLRequest. Only I am curious how I can combine TTListDataSource
together with TTNavigationCentre. Because this TTNavigationCentre
class needs a object loader instance. How is this supposed to be used
together with TTListDataSource? Currently, I am having the following
roughly the code below in the requestDidFinishLoad-selector of my
TTListDataSource descend:

{
TTURLDataResponse *response = request.response;
NSString *responseBody = [[NSString alloc]
initWithData:response.data encoding:NSUTF8StringEncoding];

// parse the JSON data that we retrieved from the server
NSDictionary *json = [responseBody JSONValue];
[responseBody release];
NSDictionary *results = [json objectForKey:@"people"];

// remove any previous items
[self.items removeAllObjects];

for (NSDictionary *result in results) {
// NSLog(@"%@",result);
[self.items addObject:[[[TTIconTableField alloc] initWithText:
[result objectForKey:@"name"] url:@"tt://people/2683" image:iconItem
defaultImage:TTIMAGE(@"bundle://DefaultAlbum.png")] autorelease]];
}

[self dataSourceDidFinishLoad];
}

BTW: I am doing the TTUrlRequest in load:nextPage.

As you can see I am using the standard TTIconTableField to add a row
to UITableView with a remote image and some text received from the
remote call (JSON). Only now I would like to be able to click through
this item and show a detailed view or maybe a level deeper. How can I
use TTNavigationCentre and the object loaders? What kind of code
should be added to the fromUrl-selector of the object loader class
e.g. People. Currently, I am doing a new TTURLRequest to obtain the
detail data from the internet instead of leveraging of the already
obtained data. What's the proper way to solve this problem?

I am not sure how to combine TTNavigationCentre, TTListDataSource
together with the TTTableFields together with these object loaders.

Yours,
Weyert

Weyert de Boer

unread,
Jun 9, 2009, 7:03:44 AM6/9/09
to Three20
Anyone? The TTNavigationCentre stuff really sounds handy for multiple
level structures. For example, I am working on a level like: Locations
> Shops > Opening Times. Now then I could use TTNavigationCentre and
let it do the pushing and popping of the view controller. Currently, I
am having a UIViewController for each type and push it to the
UINavigationControle instance. I think that's the best way to do it.
Instead of using one UIViewController and keep tracking of states and
change the datasource.

klazuka

unread,
Jun 9, 2009, 9:24:00 AM6/9/09
to Three20


On Jun 8, 8:38 pm, Weyert de Boer <wey...@gmail.com> wrote:
> What kind of code
> should be added to the fromUrl-selector of the object loader class
> e.g. People.

+ (id<TTPersistable>)fromURL:(NSURL*)url
{
// assume that url is "tt://people/2683"
// where the "tt" scheme has been registered as an internally-
dispatched
// url scheme with the TTNavigationCenter.
// and the class "People" has been registered as the object loader
for name "people".
// and the class "PeopleViewController" has been registered as the
view loader for view "people".
// and "2683" is a unique identifier of a specific person in the
recordset.

// take the path component of the URL and strip off the leading
slash, then convert it to an integer
int identifier = [[[url path] substringFromIndex:1] intValue];

return [People peopleForIdentifier:identifier];
}

+ (People *)peopleForIdentifier:identifier
{
// there are 2 situations possible:
// 1) all the data you need to create a "People" is already in-
memory (say, from a previous request to the server).
// 2) you do not have enough data, but can make a separate
request to your server to obtain the additional data.
//
// In either case, you should use |identifier| to do the lookup

#if 0
// For case 1, the identifier (2683) would be the index into the
array that was populated
// from your original request. So assuming that the data from the
original query was
// dumped into a dictionary for each person and stored in an
array |PeopleRecordSet|,
// you would do something like:

NSDictionary *personDict = [PeopleRecordSet
objectAtIndex:identifier];
return [[[People alloc] initWithDictionary:personDict]
autorelease];

#else
// For case 2, the identifier (2683) would be an id for a resource
on the server.
// and you would construct a new TTURLRequest to pull the data
down.
// Since TTNavigationCenter's object loader is designed to work in
a synchronous manner,
// you have no choice but to return a placeholder object from this
method
// after you send the new asynchronous request to get the
remaining data.
// Then when your request finishes, you could update (or replace)
the placeholder object,
// and notify any view observers that the model has changed.
// NOTE: that I do not implement the TTURLRequestDelegate methods
for you,
// that is up to you to figure out.

NSString *detailsURL = [NSURL URLWithString:[NSString
stringWithFormat:@"http://myserver.com/api/people/%d", identifier]];
TTURLRequest *request = [TTURLRequest requestWithURL:detailsURL
delegate:self];
request.cachePolicy = TTURLRequestCachePolicyDefault;
request.response = [[[TTURLDataResponse alloc] init] autorelease];
request.httpMethod = @"GET";
[request send];

return [People dummyPerson];
#endif
}


-keith

Weyert de Boer

unread,
Jun 9, 2009, 12:13:09 PM6/9/09
to Three20
Hi Keith,

Thanks! I will try out your example code snippets! Basically the
DataSource is just used by the TTTableViewController to get filled and
not to store actual model data? Because the TTListDataSource JSON
example I found on the web did the TTURLRequest in the Datasource.
Maybe I would need to make Peoples-class which retrieves the data when
needed for the first time and then keep it in memory? This singleton
instance can then be used by the People object loader and/or the
DataSource class? Then I could do [[Peoples sharedInstance]
geItem:identifier] or something in the People class.

What would you advise to be the best way to accomplice this?

Thanks in advance!

Weyert de Boer

klazuka

unread,
Jun 9, 2009, 2:00:07 PM6/9/09
to Three20
Hi Weyert,

On Jun 9, 12:13 pm, Weyert de Boer <wey...@gmail.com> wrote:
> Basically the
> DataSource is just used by the TTTableViewController to get filled and
> not to store actual model data?

No, TTDataSource will store "model" data. It will either be:
a) TTTableFields (like TTIconTableField)
b) domain objects (like an instance of your People class)

In case B, you will need to override tableView:cellClassForObject: and
tableView:prepareCell:forRowAtIndexPath: in your data source class in
order to map your domain object to an object that can be shown in the
table view. (Don't forget to call super, of course). Plus you will
need to implement a custom UITableViewCell.

In case A, TTDataSource already implements those methods to do the
right thing for TTTableFields.

> Maybe I would need to make Peoples-class which retrieves the data when
> needed for the first time and then keep it in memory? This singleton
> instance can then be used by the People object loader and/or the
> DataSource class? Then I could do [[Peoples sharedInstance]
> geItem:identifier] or something in the People class.

You basically have the right idea, but I have a few suggestions:

I would not create a separate class just to store this dataset from
the server.
Instead, at the top of People.m, declare:
static NSMutableArray *MyPeopleRecordSet;
then define some public class methods to dump data into
MyPeopleRecordSet, clear it out, and do a lookup (basically, provide
the minimal set of methods so that NSMutableArray becomes an
implementation detail).

I would still do the TTURLRequest from your data source's
load:nextPage: method. In your requestDidFinishLoad:, you can use a
class method on People to indirectly dump the data into the
MyPeopleRecordSet mutable array.

Then in +[People fromURL:] you can use the identifier from the URL to
do the lookup into MyPeopleRecordSet.

-keith
Reply all
Reply to author
Forward
0 new messages