Posts Tagged ‘sample’

Keeping your UITableViewController clean

Saturday, April 3rd, 2010

We’ve all done it, admit it, we’ve all written enormous if structures in the datasource/delegate methods of a table. It got the job done, but ever needed to change the order of the sections or needed to add/remove some rows? Things get out of hand very easily when the appearance and behavior of rows is varying. Indeed, these if structures are horrible maintenance-wise. Granted, tutorials often focus on showing some specific functionality and leave the refactoring to the reader, so aspiring iPhone developers often don’t know any better.

Here’s a way to keep your UITableViewController (or any other view controller or class your using as datasource or delegate) clean, this approach is aimed at tables with multiple sections. Tables with 1 section have limited benefit of using this approach although extra sections could be easily added later. The key is to move all the logic for a specific section in a table to its own class, which is responsible for his own rows and nothing more.

To achieve this we create a protocol called YCSectionController:

@protocol YCSectionController
 
@required
 
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
 
@optional
 
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
 
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
 
@end

This protocol will be used to specify to which methods a custom section controller must conform. Each custom section controller has knowledge about the amount of rows & how to display each row, these are the required methods. Extra methods can be added like what to do when a row is selected for instance. Depending on the appearance of the section & the desired behavior each custom section controller class implements the necessary methods.

The YCHeaderSectionController implementation below shows a minimal implementation.

@implementation YCHeaderSectionController
 
#pragma mark YCSectionController methods
 
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
	return 1;
}
 
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
	NSString *cellIdentifier = @"HeaderCell";
 
	UITableViewCell *cell = (UITableViewCell*)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil) {
		cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
		cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
	}
 
	if (indexPath.row == 0) {
		cell.textLabel.text = @"Yannick Compernol";
 
	}
 
	return cell;
}
 
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
	NSURL *url = nil;
 
	if (indexPath.row == 0) {
		url = [NSURL URLWithString:@"http://yannick.compernol.be"];
	}
 
	if (url) {
		[[UIApplication sharedApplication] openURL:url];
	}
}
 
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
	return @"Info";
}
 
@end

One you’ve made several custom section controllers all you have to is to hook them up in your UITableViewController and dispatch the datasource/delegate methods to the custom section controllers. Note the UITableViewControllers has an array which will hold all the custom section controllers, the array is filled in the ViewDidLoad: method.

@interface MainTableViewController : UITableViewController {
	NSArray *sectionControllers;
}
@end
 
@implementation MainTableViewController
 
...
 
#pragma mark UIViewController methods
 
- (void)viewDidLoad {
    [super viewDidLoad];
 
	id header = [[YCHeaderSectionController alloc] init];
	id content = [[YCContentSectionController alloc] init];
	id footer = [[YCFooterSectionController alloc] init];
 
	sectionControllers = [[NSArray alloc] initWithObjects:header, content, footer, nil];
 
	[header release];
	[content release];
	[footer release];
}
 
...
 
#pragma mark UITableViewDataSource methods
 
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
	return [sectionControllers count];
}
 
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
	id<YCSectionController> sectionController = [sectionControllers objectAtIndex:section];
	return [sectionController tableView:table numberOfRowsInSection:section];
}
 
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
	id<YCSectionController> sectionController = [sectionControllers objectAtIndex:indexPath.section];
	return [sectionController tableView:tableView cellForRowAtIndexPath:indexPath];
}
 
...
 
#pragma mark UITableViewDelegate methods
 
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
	id<YCSectionController> sectionController = [sectionControllers objectAtIndex:indexPath.section];
	if ([sectionController respondsToSelector:@selector(tableView:didSelectRowAtIndexPath:)]) {
		[sectionController tableView:tableView didSelectRowAtIndexPath:indexPath];
	}	
}
 
@end

And that is about it, it can be taken further than I showed here, but I think this is a decent starter. The bottom line is that the UITableViewController has less code and the specific code (appearance & behavior) for each section is contained in its own class. Adding to the maintainability of the whole table.

A running example (screenshot shown above) can be downloaded here.

There’s only one thing I’m still struggling with, since id does not have a respondsToSelector: method, you’ll get a warning that respondsToSelector: wasn’t found in the protocol. An easy fix would be to add it to the protocol, but that doesn’t feel right as it’s not part of the behavior I wanted to encapsulate in the section controller. I’d love to hear your thoughts/comments on this!

Basic authentication of a .NET REST service

Tuesday, July 28th, 2009

One of the issues one can encounter when building a REST service with the .NET Framework 3.5 SP1 is the fact that when basic authentication is enabled, it defaults to authentication against Windows accounts in IIS. It’s not possible to specify your own handler/provider to authenticate against for instance a proprietary user database, nor is it possible to secure only a certain operation/service and leave the others unsecured.

Luckily there’s a open source project hosted on CodePlex called WCF REST Contrib which, besides adding a whole lot of other improvements, solves the aforementioned issues. The project provides a sample solution showcasing all the features, which might seem a bit overwhelming since it includes quite some configuration. I have attached a sample project with only the bare minimum configuration (using attributes) to enable per operation authentication.

Browse to CancerService.svc/request/skincancer to test the authentication, the browser should display a prompt asking for a username and password. The username is “tony” and password “clifton”. Don’t mind the rather questionable service and operation name, I had no inspiration at the time.

The original documentation failed to mention that the per operation/service authentication depended on the WebErrorHandler, which has been corrected.

Attachment: Authentication Tryout