Thursday, November 14, 2013

Subclass, Category and Extensions in Objective C

Today lets see what is subclassing, categories and extensions in Objective C, and where, when and how to use these concepts.

Note: A complete working Xcode project copy is available for download, which includes all the required examples to understand these concepts practically at the end of this post.

1) Subclass in Objective C

Subclassing in simple words is changing the behavior of properties or methods of an existing class or in other words subclassing is inheriting a class and modifying the methods or properties of super class however you want.

Suppose for example consider a UITextField class, by default the placeholder text of UITextField will be of light gray color with default system font. If we want to change this style just subclass UITextField and override drawPlaceholderInRect method.

Example:
Create a class of type UITextField and name it some thing like CustomUITextFieldPlaceholderAppearance

CustomUITextFieldPlaceholderAppearance.h
#import <UIKit/UIKit.h>
@interface CustomUITextFieldPlaceholderAppearance : UITextField
@end

CustomUITextFieldPlaceholderAppearance.m
#import "CustomUITextFieldPlaceholderAppearance.h"

@implementation CustomUITextFieldPlaceholderAppearance
// override drawPlaceholderInRect method
- (void)drawPlaceholderInRect:(CGRect)rect {
    // Set color and font size and style of placeholder text
    [[UIColor redColor] setFill]; //set placeholder text color to red
    [[self placeholder] drawInRect:rect withFont:[UIFont fontWithName:@"verdana" size:14.0]]; //set custom font style and size to placeholder text 
}
@end

Now in your application wherever you want this custom look and feel for placeholder text of textfield you can just import this subclass header file (#import "CustomUITextFieldPlaceholderAppearance.h") and create an object of this class and you are done. In addition to this look and feel the default delegate methods and properties of UITextField will remain same.

2) Categories in Objective C

An Objective C category allows you add your own methods to an existing class.

Categories are also called as "informal protocols".

Suppose take an example, since Foundation Framework classes such as NSString, NSArray, NSDate etc… doesn’t have any access to modify, you can add your own methods in to these classes by the help of a category.

Consider NSString Class and if suppose we want to add a reverse string method to NSString class, so that in our application at any point of time any NSString object can call this category method and get a reversed string as a result. We can do this as below,

Note: Usually naming convention for category file is like OriginalClassName+CategoryName

Example:
Lets create a category class with a name something like NSString+NSString_ReverseString

NSString+NSString_ReverseString.h
#import <Foundation/Foundation.h>

@interface NSString (NSString_ReverseString)
- (NSString *)reverseString:(NSString *)yourString;
@end

NSString+NSString_ReverseString.m
#import "NSString+NSString_ReverseString.h"

@implementation NSString (NSString_ReverseString)

- (NSString *)reverseString:(NSString *)yourString
{
    NSMutableString *reversedStr = [NSMutableString stringWithCapacity:[yourString length]];
   
    [yourString enumerateSubstringsInRange:NSMakeRange(0,[yourString length])
                                 options:(NSStringEnumerationReverse | NSStringEnumerationByComposedCharacterSequences)
                              usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                                  [reversedStr appendString:substring];
                              }];
    return reversedStr;
} 
@end

Now in your application wherever you want  to reverse a string then just import this category header file (#import "NSString+NSString_ReverseString.h"
) and call our reverseString: method from any of NSString object and it will reverse and return you the reversed string.

In the above example we have added a custom method called reverseString: to NSString class from the help of a category.

Note that in a category you can’t add an instance variable, since methods within a category are added to a class at runtime.

3) Extensions in Objective C

Extensions are similar to categories but the need of extension is different.
- Class extensions are often used to extend the public interface with additional private methods or properties for use within the implementation of the class.
- Extensions can only be added to a class for which you have the source code at compile time (the class is compiled at the same time as the class extension).
- Extensions will be local to a class file.

The syntax to declare class extension looks like,
@interface ClassName()

@end
since no name is given in the parentheses, class extensions are often referred to as anonymous categories.

Note Extensions can add instance variables.
Example:
@interface ABCExtension()
@property NSObject *yourProperty;
@end

the compiler will automatically synthesize the relevant accessor methods, as well as an instance variable, inside the primary class implementation.
If you add any methods in a class extension, these must be implemented in the primary implementation for the class.

Example:
In any of your class in implementation file(.m), say ViewController.m
@interface ViewController ()
-(void)printName:(NSString *)name;
@end

@implementation ViewController
-(void)printName:(NSString *)name
{
    NSLog(@"%@",name);
}

In the above extension example printName: method is private to class ViewController,  and cannot be accessed from outside the ViewController class.(even if you inherit since printName: is a private method their will not be any access to this method outside the class)

You can call this extension method only inside ViewController class, as below
[self printName:@"MyName"];

Usually people will use extensions to hide private information of a class without exposing them to access from any other class.

Finally few simple points to remember is 
- Subclassing is better option if you want to customize an existing stuffs or functionalities, and
- Category is a best option if you want to add additional functionalities to an existing class

You can download a Sample Xcode Project here.

Hope this post was helpful, any comments or suggestions is acceptable.

39 comments:

  1. Replies
    1. @Udimudi Hemaraju , My pleasure... :)

      Delete
  2. Hey Arun Superb.... Hope you remember me :)

    ReplyDelete
    Replies
    1. @Vinay Kumar Thanks maga, Hey of course maga I do remember :)

      Delete
    2. Awesome man....really impressed 😀

      Delete
  3. What happens if we override drawPlaceholderInRect:(CGRect)rect in category?

    will it become again inheritance?

    ReplyDelete
    Replies
    1. First thing is Category design pattern is to add your own custom methods for existing classes not to override methods. Secondly you are not allowed to override private methods of Apple predefined classes, it violates the basic principles of Apple and their are more chances of getting rejected in review of your app by Apple, if you do so.

      Delete
  4. great tutorial man ...!!

    ReplyDelete
  5. Nice tutorial.....................

    ReplyDelete
  6. Hi Arun, nice tutorial. But I have one doubt regarding subclass, in the above example you said to create an object of class "CustomUITextFieldPlaceholderAppearance". So is it enough if I just create an object like this , CustomUITextFieldPlaceholderAppearance *textField = [[CustomUITextFieldPlaceholderAppearance alloc] init]; ? and should i call a method of this class "drawPlaceholderInRect:(CGRect)rect" ?

    ReplyDelete
    Replies
    1. Hey, thanks man :), and coming to your doubt, you no need to call drawPlaceholderInRect method and it is not recommended as well.
      You just need to create an object of your subclass like "CustomUITextFieldPlaceholderAppearance *myTextField = [[CustomUITextFieldPlaceholderAppearance alloc] init];" and use this "myTextField" object.
      Hope this clarifies your doubt.

      Delete
    2. Yep cleared my doubt and Thank you so much for the quick reply :)

      Delete
  7. This comment has been removed by the author.

    ReplyDelete
  8. HI Arun,

    Really very nice sharing,you clear my all doubt.Thanks for sharing.

    Sourabh

    ReplyDelete
  9. Hi Arun, Its very clear.. Nice Explanation.. Please continue posting

    ReplyDelete
    Replies
    1. @Subhashini Mohan, Thanks a lot, sure I will try to keep posting more stuffs.

      Delete
  10. Hi,

    I have a small question, here we are taking a new class that is NSString+NSString_ReverseString.h, without taking NSString+NSString_ReverseString.h , why can't we have a class method which does the same thing, what exact category role plays here? kindly explain.

    ReplyDelete
    Replies
    1. Hi @bharathreddy vasipalli,
      If you implement the same functionality within a class as a class method, then the scope of "reverseString" method will be only within that particular class, you can’t use it as a generic “reverseString” method throughout your application.

      But if you implement category pattern and add the additional methods to a existing Cocoa Touch class then the scope of that particular category methods is throughout your application.
      By following these kind of patterns while you are developing your app the main advantage is your code will be independent of any entities, In other words - “loosely coupled” and flexible enough(easier) for future modifications or updations.
      Hope I have clarified your doubt. Cheers :)

      Delete
    2. Arun@ Really it helps me a lot.. Thanks a ton.

      Delete
    3. +Bharath Reddy, My pleasure :)

      Delete
  11. Very nice tutorial... good job. Can u please share something regarding protocols, encapsulation,polymorphism, with some examples, exactly in the same way as u did in this tutorial. Thanks in advance..
    Once again, i must say, superb tutorial.

    ReplyDelete
    Replies
    1. @Amit Thakur, My pleasure :), Yup definitely will try to cover those topics soon.

      Delete
  12. Just fabulous.. Your examples help in remembering things for a long term.. :)

    ReplyDelete
    Replies
    1. @Anonymous, Thank you, My pleasure :)

      Delete
  13. Hi sir,

    It's very good tutorial. Thanks

    ReplyDelete
  14. Really greate tutorial arun

    ReplyDelete
  15. Nice tutorial Aman thanks,
    Are u in swift ? i want to learn it , can u help me out ?

    ReplyDelete