Top of the page
Close

This is a red error

This is a red error

This is a red error

Using Categories in Objective-C to extend native classes / objects from iPhone SDK

Ondrej Rafaj on 2010.02.04 19:36:51

Attached files
Categories in Objective.docx Download
Categories.zip Download

Hi, today I would like to explain how to extend classes from the iPhone SDK frameworks. The main idea behind that is not to create loads of classes, one for each functionality, but create custom extensions for the existing ones.

In this example we will be working with class NSString that, as I assume you know very well, or at least you know what this thing do.

Basic usage of NSString class is:

NSString *myString = [[[NSString alloc] init] autorelease];
myString = @"This is my string";
int a = [myString length]; 

This is just creating and allocating new instance of our NSString class and releases it automatically once the myString variable is no longer needed. We are setting the string value for it and than using non-static function length that return number if characters in the string.

We can also use a static function inside of the NSString object:

NSString *myString = [NSString stringWithFormat:@"Format of my %@", @"myString"];

This line will set string value for variable myString to "Format of my myString" These were just the main basic functions you can find in the documentation, but now imagine that you have a repetitive task and every time you want to call it, you have to write few lines of code and if you’ll need to change anything in the future, you have to go trough your code and change the functionality manually everywhere. Yeah you might be right, we can close this piece of functionality into the function, create a class for it. Ok, that’s one way, another one, much more elegant is to extend already existing class, and I don’t mean extend like that:

@interface MyExtendedNSString : NSString

when you are just creating another class which is inheriting properties from it’s parent, but now we are going to add functions to the main NSString class.

Lets say that this annoying repetitive task we want to use is to retrive some text data from the server, we want to send an URL as a string and get string as a result.

First thing you have to do is to create two new files, in this example we will be creating static function called stringWithUrlInUtf8 than I’ll include all the important information in the name of the file. Create NSString+URL.h and NSString+URL.m files and edit the .h file first.

Content of this file will be:

//
//  NSString+URL.h
//  TutorialProject
//
//  Created by Ondrej Rafaj on 4.2.10.
//  Copyright 2010 xProgress.com; All rights reserved.
//

@interface NSString (urlTools)

+ (NSString *)stringWithContentsOfUrlInUtf8:(NSString *)targetUrl;

@end

The name urlTools isn't very important. It’s an arbitrary identifier. Its only requirement is that it must be unique for the class it’s being applied to. Content of the .m file is here:

//
//  NSString+URL.m
//  TutorialProject
//
//  Created by Ondrej Rafaj on 4.2.10.
//  Copyright 2010 xProgress.com; All rights reserved.
//

#import "NSString+URL.h"

@implementation NSString (urlTools)

+ (NSString *)stringWithContentsOfUrlInUtf8:(NSString *)targetUrl {
	NSLog(@"URL in String: %@", targetUrl);
	NSURL *location = [NSURL URLWithString:targetUrl];
    NSError *error = nil;
	NSString *content = [NSString stringWithContentsOfURL:location encoding:NSUTF8StringEncoding error:&error];
	if (error) NSLog(@"Something went wrong %d, %@", [error code], [error localizedDescription]);
	return content;	
}

@end

And the usage is really simple, you just have to include the header file of our Category class and than you will be able to use your functions in the same way as you are using other methods from the NSString object.

Tutorial main controller file is here:

//
//  TutorialProjectViewController.h
//  TutorialProject
//
//  Created by Ondrej Rafaj on 5.8.09.
//  Copyright Home 2009. All rights reserved.
//

#import 

// ------ Tutorial code starts here ------

#import "NSString+URL.h"

// ------ Tutorial code ends here ------

@interface TutorialProjectViewController : UIViewController {
	
	// ------ Tutorial code starts here ------
	
	IBOutlet UITextField *originalUrl;
	IBOutlet UITextView *urlContent;
	
	// ------ Tutorial code ends here ------
	
	
}

// ------ Tutorial code starts here ------

@property (nonatomic, retain) IBOutlet UITextField *originalUrl;
@property (nonatomic, retain) IBOutlet UITextView *urlContent;

- (IBAction) getUrlContent:(UIButton *)sender;

// ------ Tutorial code ends here ------

// This function is for button which takes you to the xprogress.com website
- (IBAction) runXprogressComButton: (id) sender;

@end

And our .m file is here:

//
//  TutorialProjectViewController.m
//  TutorialProject
//
//  Created by Ondrej Rafaj on 5.8.09.
//  Copyright Home 2009. All rights reserved.
//

#import "TutorialProjectViewController.h"

@implementation TutorialProjectViewController

// ------ Tutorial code starts here ------

@synthesize originalUrl, urlContent;


// Hide keyboard while the Return button is hit
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
	[textField resignFirstResponder];
	return NO;
}

// Get data using our stringWithContentsOfUrlInUtf8 function
- (IBAction) getUrlContent:(UIButton *)sender {
	
	// Now we are using our function as a part of the NSString object
	self.urlContent.text = [NSString stringWithContentsOfUrlInUtf8:[self.originalUrl text]];
	
}

// ------ Tutorial code ends here ------


/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        // Custom initialization
    }
    return self;
}
*/

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/


/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
}
*/


/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/

- (void)didReceiveMemoryWarning {
	// Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
	
	// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
	// Release any retained subviews of the main view.
	// e.g. self.myOutlet = nil;
}

// This function is for button which takes you to the xprogress.com website
- (IBAction) runXprogressComButton: (id) sender {
	NSURL *url = [[[NSURL alloc] initWithString: @"http://www.xprogress.com/"] autorelease];
	[[UIApplication sharedApplication] openURL:url];
}


- (void)dealloc {
    
	// ------ Tutorial code starts here ------
	
	[originalUrl, urlContent release];
	
	// ------ Tutorial code ends here ------
	
	[super dealloc];
}

@end

You’ll find the example application in the right top corner of this tutorial and printable MS Word version is also available.

I hope that you do understand what I’ve been trying to explain, if there will be any problem or confusion (and I can be really confusing sometimes :))), I’ll be more than happy to help you guys, just post a comment bellow this article.

Cheers,

Ondrej

Ondrej Rafaj

Ondrej Rafaj

Technical director @ Fuerte International

Back to top Comment

Comments ... Why not to get involved!
HTML Comment Box is loading comments...

Old comments:

Back to top

IE SUCKS, DON'T USE IT :) Digg this page