IOS and Rails web dev at Intotheweb. Follow me on twitter @brunow

UITableView Dynamic cell mapping like Restkit[EDIT]

I love the JSON object mapping from RestKit and recently RestKit create a new library that map dynamically object property with cell ui property. But i thought that the RestKit solution was too complicated. So I decide to do my own cell mapper. You can found BaseKit on Github.

Add BaseKit to your project

That's really easy. Just drag the dir Code/Core, Code/View and Code/CellMapping into your project.

Next step create an object that will store data from the cell.

Create a class called Movie.

Movie.h

@interface Movie : NSObject

@property (nonatomic, retain) NSString *title;
@property (nonatomic, retain) NSString *subtitle;
@property (nonatomic, readonly) NSString *imageName;

+ (id)itemWithTitle:(NSString *)title subtitle:(NSString *)subtitle;

@end

Movie.m

@implementation Movie

@synthesize title = _title;
@synthesize subtitle = _subtitle;

- (void)dealloc {
    self.title = nil;
    self.subtitle = nil;

    [super dealloc];
}

+ (id)itemWithTitle:(NSString *)title subtitle:(NSString *)subtitle {
    Item *item = [[self alloc] init];

    item.title = title;
    item.subtitle = subtitle;

    return [item autorelease];
}

- (NSString *)imageName {
    return @"tux.png";
}

@end

The table view cell

Create one simple cell called MovieViewCell that inherit from UITableViewCell. The only thing you have to do here, is:

+ (UITableViewCellStyle)cellStyle {
    return UITableViewCellStyleSubtitle;
}

Sa that you can use cell.detailTextLabel and cell.imageView properties. Read the UItableViewCell category to learn more about that.

Last step: create the table view controller

TableViewControllerExample.h

@interface TableViewControllerExample : UITableViewController<BKTableModelDataSource>

@property (nonatomic, retain) BKTableModel *tableModel;
@property (nonatomic, retain) NSArray *items;

@end

TableViewControllerExample.m

@implementation TableViewControllerExample

@synthesize tableModel = _tableModel;
@synthesize items = _items;

- (void)viewDidLoad {
    [super viewDidLoad];

    self.items = [NSArray arrayWithObjects:
                  [Item itemWithTitle:@"Movie1" subtitle:@"First movie"],
                  [Item itemWithTitle:@"Movie2" subtitle:@"Second movie"],
                  [Item itemWithTitle:@"Book1" subtitle:nil],
                   nil];

    self.tableModel = [BKTableModel tableModelForTableView:self.tableView];

    [BKCellMapping mappingForObjectClass:[Movie class] block:^(BKCellMapping *cellMapping) {
        [cellMapping mapKeyPath:@"title" toAttribute:@"textLabel.text"];
        [cellMapping mapKeyPath:@"subtitle" toAttribute:@"detailTextLabel.text"];

        [cellMapping mapKeyPath:@"imageName" toAttribute:@"imageView.image" valueBlock:^id(NSString *value) {
            // Because imageName is of type NSString and imageView.image of type UIImage
            return [UIImage imageNamed:value];
        }];

        [cellMapping mapObjectToCellClass:[MovieViewCell class]];
        [self.tableModel registerMapping:cellMapping];
    }];

    [self.tableModel objectForRowAtIndexPathWithBlock:^id(NSIndexPath *indexPath) {
        return [self.items objectAtIndex:indexPath.row];
    }];
}

- (void)viewDidUnload {
    [super viewDidUnload];

    self.tableModel = nil;
    self.items = nil;
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.items.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    return [self.tableModel cellForRowAtIndexPath:indexPath];
}

BKCellMapping has a lot of more fonctionalities. For example loading nib and perform dynamic mapping. You can found more example here.