Here is how to extend the functionality of existing classes like NSString and NSURL using categories. This is a real clean way to extend and customize objects for your app without creating sub-classes. This makes categories a nice way to get some flexibilty and code reuse.
For the demo I am going to create a make-shift HTML editor by extending the NSString classes with methods that enclose text inside of HTML tags. The app will do this and display the results in an UIWebView.
Here is a quick overview of what the app will do:
Categories are a clean way of adding behavior that belongs to a class but only in a specific implementation. You can use a class to add special methods just for one region in your app that does not belong everywhere else. In the example I am using I want to be able to quickly add HTML tags to certain strings, but this is not something that generally belongs as a function of NSString.
So my app needs HTML support and it logically belongs in NSString for this purpose. But, I don’t want all my apps to have this option nor do I want to have to use a special sub-class of NSString throughout this component (because I will never remember to do this later on). With categories I can define my own behavior for a class and then selectively apply this behavior to classes in my apps when needed.
Now, let’s implement the HTML Writer App Using Categories.
As a side note I simply used Interface Builder to lay this UI out and hook the components up to the respective IBOutlets and IBActions. Something I so also is get each UIButton’s tag property so I can identify it later on in code. This will be used to identify what tag should be wrapped around the text.
To start extending NSString all you need to do is to add interface and implementation files and add this code:
Interface File
Implementation File
This looks a bit like a typical class definition but it is different. Here after the interface you will see the name of the class that you want to extend (NSString) followed by the name of the category (NSString_HTML). Other than that this code should look familiar.
BTW: I could have simply included this interface and implementation directly in the file where I want to use the category. However, since I may want to reuse this code in the future I felt that it makes more sense to keep it in another file.
To make things easier on myself I am going to define some integers that will serve as the HTML tags that I am supporting: p, h1, h2, i and u. I will do this in the interface:
This is where we add the extended functionality to NSString. I am going to add a method to the category just like I would for a regular class:
Interface
Implementation
Now that I have everything in place all I need to do is the actual implementation of the method. I am simply going to enclose the string based on the integer tag that is passed as a parameter to the method. I will also use the self keyword to identify the string itself. Here is an example of the general pattern that I am following:
This is the complete implementation of the method:
Now that we have defined the method to add tag support to NSString we can use it anywhere in our project. All we need to do is import the category and use the method. Here is how I did this in my view controller:
I did omit some of the code here for clarity. Essentially, at the top I imported NSString_HTML.h which makes the stringWithThisTag method available to me. Then I use the new function at the end where I pass the tag property of the button that fired the event as a parameter (each UIButton was tagged with an integer that corresponds to the integer that my new function needs to figure out which tag to use).
Check out this video tour of all this code in action as well as some other tweaks that I did with NSURL:
Discuss in the comments below!
This post came in very handy today. Why? Well because I finished reading about Categories in the Cocoa Design Patterns. So it was since to see it in action. Thanks again!
@hawk – awesome I’m glad that you liked it.
BTW: Did you find Cocoa Design Patterns to be a good read? That one is on my list and I have a feeling that it would be really helpful…
Nice tutorial, but I’m not sure I understand the differences between subclassing and categories. Are categories used just so you don’t have to instantiate a subclassed object to get added functionality? Or is it required in this instance because the text component can only work with an NSString?
@webXL – you can use sub-classing and categories for similar problems and the difference is pretty subtle in a lot of ways. It is not really required and you could do a similar thing if you sub-classed NSString and used that object in place of a NSString object.
Essentially though, the main thing is that when you are using categories you don’t need to worry about replacing your NSString objects with a subclassed version of NSString.
This way, when you already have objects in play (such as the text property of my UITextView) you can simply import the category and you have the functionality available to you automatically.
You must be logged in to post a comment.
Learn How To Make An iPhone App right now using my proven system.
PS: Tons of us are having a blast living off our own code, join us now. Click here to get all the details.