Archive for the ‘Cocoa Touch’ Category

Converting NSData to NSString and vice versa

Wednesday, June 23rd, 2010

Since I always forget how to convert a NSData object to NSString and vice versa, I thought I’d write it down as a reference. Every time I work with a REST service and need to know what response I’m receiving, before handing the NSData object to a NSXMLParser, I’m always dumbfounded that I’ve forgotten how to do the conversion.

// From NSString to NSData
NSString *text = @"Some string";
NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding];
 
// From NSData to NSString
NSString *text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

Who knows if it helps some one else.

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!

Multiline cells in iPhone SDK 3.0

Sunday, June 21st, 2009

While surfing the web and browsing through development related forums, I encountered a lot of questions regarding multiline UITableViewCells. Prior to iPhone SDK 3.0 this was not an easy feat and although it is very common in UIs, the work that is related to creating multiline cells is not proportional to how common they are.

Apple definitely made it easier with new SDK, since we can interact directly with the UILabel. I know it’s pretty straightforward, but I’m always surprised by how many developers disregard the documentation & turn to forums/blogs for help.

Creating multiline cells is now as simple as setting the numberOfLines property to 0 (or a predefined number) of the textLabel, which is in turn a property of the cell. Given the height of the cell is sufficient, behold a multiline cell.

cell.textLabel.text = @"Some long text...";
cell.textLabel.numberOfLines = 0;

Change the height of the cell with the tableView:heightForRowAtIndexPath: delegate method of the UITableViewController, either by returning a fixed height or by calculating the height needed to show the desired text.

Note that the text property of a cell is being deprecated in favor of textLabel.text, more info on the new 3.0 predefined cell styles can be found here.

Load view from nib improvement

Monday, May 11th, 2009

One of the constants in a developer’s life is seeing code and knowing you’re doing it wrong, but not really knowing how to fix it and get it right. Due to whatever reason: no time… My Facebook like loading indicator article was no exception, the way I loaded a specific view from a separate nib felt so bad. Yet I posted it since holding it back for another 4 weeks was no option either. A week ago I had a eureka moment and it all made sense at around 2am on a Saterday morning. Here’s the correct method to load a view from a separate nib file.

Instead of looping through the contents of the nib, the key are IBOutlets. Create a NSView IBOutlet in your controller class were you’ll want to use the view. Next step is to open your nib file which contains your external view and change the File Owner’s class identity to the controller class you’ve just extended with the IBOutlet for the view. Now just ctrl-drag from the File Owner to your view and select your desired IBOutlet from the list.

Now you’ve connected your controller and the external view, yet the IBOutlet will not be hooked up automatically when your controller’s created. This is a good thing because we can postpone loading the extra nib to when it’s really necessary saving resources for other, more important stuff. This is a practice Apple encourages, using multiple nib files and loading them dynamically when needed.

This is the code needed to load the nib, it’ll automaticall hook up your controller’s IBOutlet to your view.

[[NSBundle mainBundle] loadNibNamed:@"YourNibName" owner:self options:nil];

Simple? Indeed, yet it took me a while to realize using an external nib is basically just the same as putting all your views in a single nib container. It’s all based on hooking up IBOutlets.

Facebook like loading indicator

Saturday, April 25th, 2009

When performing an action that may take some time, it’s advised to show something to signal that the operation is being performed & the application is not crashing. Here’s an example on how to accomplish a loading indicator as used in the iPhone Facebook application.

Loading View

First we’ll create the actual loading view, let’s add an empty XIB to our Xcode project called LoadingView. Add a UIView to the nib and drag a UIImageView onto it. Use a vector program like Inkscape to create a black rectangle with rounded corners. Use a UILabel and a UIActivityIndicator to create something like the screenshot to the right. Be sure to check the animating property of the activity indicator and change the alpha of the root view to 0.8 for intance, since we want the view to be slightly transparant.

Once we’ve made the actual view, it’s time to show it.

- (UIView*)newLoadingView {
   NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"LoadingView" owner:self options:nil];
 
   NSEnumerator *enumerator = [nib objectEnumerator];
   id object;
 
   while ((object = [enumerator nextObject])) {
      if ([object isMemberOfClass:[UIView class]]) {
         return object;
      }
   }
 
   return nil;
}
 
- (void)doWork {
   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
   // Add lenghty operation.
 
   [loadingView removeFromSuperview];
   [pool release];
}
 
- (void)someMethod {
   loadingView = [self newLoadingView];
   loadingView.center = CGPointMake(160, 350);
   [self.view addSubview:loadingView];
 
   [NSThread detachNewThreadSelector:@selector(doWork) toTarget:self withObject:nil ];
}

We’re using the newLoadingView: method to retrieve the view from the nib, the reason we’re looping through the contents of the nib is one cannot garantee the order in which items are retrieved will always be the same. For instance the index of the loading view will be different in firmware version 2.0 and 2.1. We retrieve a UIView item, in this case the loading view, since it’s the only UIView in the nib. I’m sure this code could be improved though, using your own derived UIView and checking for this derived class would be better. The center property of the loading view can be used to position the view, the top left corner has coordinates 0,0. (If anyone has a better method of getting a specific view from a nib, do tell)

The someMethod method is the one to call to start everything, this method will show the actual loading view and start the doWork method on a seperate thread. The reason we’re using a seperate thread is not to lock up the interface, otherwise the interface would freeze while the lenghty operation would be performed. The doWork method hides the loading view once everything is done.

Extension: The above code has one disadvantage, when using a tab controller the loading view will disappear once another tab is selected, returning to the original tab will show the loading view again though. In some cases this behaviour isn’t wanted, how do we solve this? Instead of showing the loading view on top of the content view displayed by the tab controller, we’ll show it on top of all the views, on top of the tab controller.

// Show loading view on top of everything
[[UIApplication sharedApplication].keyWindow addSubview:loadingView];

And that’s all there is to it.

Update: here’s the correct method to load a view from a separate nib file.

New line in UILabel and UITextView

Monday, March 23rd, 2009

Somehow I never figured out how to insert a new line in a UILabel or UITextView, up until now. A new line is added with Alt + Enter. Using Enter only while editing the text will result in a new line in editing mode, but the new line is lost when editing mode is quit.

There you have it.

Multiple async NSURLConnections example

Sunday, March 15th, 2009

After posting the custom NSURLConnection subclass blog post, I thought I might post an example of how it would be used, since quite a lot of visitors came to the blog searching for the keywords: “multiple asynchronous NSURLConnection”. The code itself is pretty straightforward, but might prove handy for those developers setting their first steps in Cocoa Touch.

The basic idea is to use a dictionary which stores the received data per tag, remember that the actual connection cannot be used as the key of a dictionary. Each NSURLConnection methods retrieve the NSMutableData object from the dictionary based on the tag and does it magic with it.

If you don’t know how to use the NSURLConnection class, take a look at the documentation. That should get you going in no time.

First of all add a mutable dictionary to the header file:

NSMutableDictionary *receivedData;

Here’s the actual code. The load method starts the actual asynchronous calls. The startAsyncLoad:tag and dataForConnection methods are convenience methods to keep the code tidy & readable.

- (void)startAsyncLoad:(NSURL*)url tag:(NSString*)tag {
   NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
   CustomURLConnection *connection = [[CustomURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES tag:tag];
 
   if (connection) {
      [receivedData setObject:[[NSMutableData data] retain] forKey:connection.tag];
   }
}
 
- (NSMutableData*)dataForConnection:(CustomURLConnection*)connection {
   NSMutableData *data = [receivedData objectForKey:connection.tag];
   return data;
}
 
- (void)load {
   receivedData = [[NSMutableDictionary alloc] init];
 
   NSURL *url1 = [NSURL URLWithString:@"http://blog.emmerinc.be"];
   NSURL *url2 = [NSURL URLWithString:@"http://www.emmerinc.be"];
   NSURL *url3 = [NSURL URLWithString:@"http://twitter.com/emmerinc"]; 
 
   [self startAsyncLoad:url1 tag:@"tag1"];
   [self startAsyncLoad:url2 tag:@"tag2"];
   [self startAsyncLoad:url3 tag:@"tag3"];
}
 
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
   NSMutableData *dataForConnection = [self dataForConnection:(CustomURLConnection*)connection];
   [dataForConnection setLength:0];
}
 
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
   NSMutableData *dataForConnection = [self dataForConnection:(CustomURLConnection*)connection];
   [dataForConnection appendData:data];
}
 
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
   NSMutableData *dataForConnection = [self dataForConnection:(CustomURLConnection*)connection];
   [connection release];
 
   // Do something with the dataForConnection.
}

In the connectionDidFinishLoading: method the tag of the connection should be used to determine what to do with the actual received data. And that is about it!

Don’t forget to release the dictionary in the deconstructor or after all the asynchronous calls have been completed though.

iPhone (game) development links

Thursday, March 5th, 2009

A collection of links/blogs I gathered in the course of the last month regarding iPhone (game) development and some other useful things. Probably of the most value to beginning iPhone developers.

Blog: Cocoa with Love
Includes an asteriods style game in CoreAnimation how to.

Blog: CrystalMinds
Includes a Duck Hunt game with regular UIViews how to.

Documentation: Create a singleton instance
Apple documentation on how to create a singleton instance.

Code snippets: iPhone SDK Examples
Some simple but useful examples.

Blog: iPhone Development
Decent blog with some good articles.

Forum: iPhone Dev SDK
One of the largest forums regarding iPhone (and Mac) development, contains an interesting business sub-forum.

Blog: iPhone Developer Tips
Another active and useful blog.

Blog: iPhone Development Bits
Has some nice links to other articles including a little game.

That’ll be it for now.

Custom NSURLConnection class with tag

Monday, March 2nd, 2009

A caveat one quickly encounters when using multiple asynchronous NSURLConnections with the same target delegate is that there is no easy way to distinguish one connection from the other, in for instance the connection:didReceiveData: method.

Since using multiple asynchronous connections implies handling the received data chunks yourself, one is likely to create a dictionary which contains a NSMutableData object for each NSURLConnection key. Unfortunately does a NSDictionary copy its keys and this is not something a NSURLConnection supports. A quick solution to avoid this is to make a subclass with a tag to distinguish each connection. This tag can be used as key in the dictionary.

Interface:

@interface CustomURLConnection : NSURLConnection {
   NSString *tag;
}
 
@property (nonatomic, retain) NSString *tag;
 
- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString*)tag;
 
@end

Implementation:

@implementation CustomURLConnection
 
@synthesize tag;
 
- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString*)tag {
   self = [super initWithRequest:request delegate:delegate startImmediately:startImmediately];
 
   if (self) {
      self.tag = tag;
   }
   return self;
}
 
- (void)dealloc {
   [tag release];
   [super dealloc];
}
 
@end

As you can see, creating a subclass with a tag property is rather easy and solves the dictionary issue.

Parsing serialized .NET DateTime to NSDate

Wednesday, February 25th, 2009

In my application I have to parse a serialized .NET DateTime returned from a REST service to a NSDate object. I expected to be able to use the initWithString: constructor of the NSDate class, but this wasn’t the case. The initWithString: constructor expects a string with the following format “2009-02-25 22:00:00 +0100″, yet the serialized .NET DateTime is in the following format “2009-02-25T22:00:00+01:00″. Notice the “T” and the semicolon in the timezone offset.

To solve this difference in format, one could manipulate the actual string to comply to the desired format or one could use the NSDateFormatter class. The latter being the “cleanest” solution.

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZ"];
NSDate *date = [formatter dateFromString:text];

The used format patterns comply to the Unicode standard UTS #35.