Sunday, 24 February 2013

Introduction to Modern Objective C

Hello friends!! In this post I am going to talk about Modern Objective C. It comes with Xcode 4.5 and it is a feature of LLVM Copiler 4.0 so if you don't have Xcode 4.5, then please update your Xcode to latest version. This tutorial assume that you have prior knowledge of Objective C, if you don't know Objective C then you can start here Objective-C Programming Guide.

         Modern Objective C does not introduce any new construct but it simplify the common Objective C programming pattern, makes program more concise and avoids making common mistakes. More frankly it improve the safety of  container creation. 

Now lets start with some coding and see all the feature introduce in Modern Objective C. First create a project using xcode and name it as  "ModernOBJCTest".

1. File --> New Project --> Single View Application --> On Screen Instruction


Property Synthesis


    In Modern Objective - C you do not need to synthesize the properties, xcode will do it for you. So now you can say bye, bye to "@synthesize" keyword.

  • Name of instance variable in default synthesis will be underscore ('_') prefixed 
  • You need to define the name of instance variable if you are defining custom accessor and setter

Private Methods


    Till now what are you doing for private methods? Have you defined it in interface file(.h file) Yes!! no no... its not a good idea, sorry but please read the basic of OOPs, if No, you are a good programmer and i think you have defined it in category YES!! its cool but now forget it too, because you can write your private methods in implementation file (.m file) without declaring it in interface file or in a category. Thanks to xcode you don't have to worry about order of methods because at time of compilation xcode buffers the body of methods and looks for signatures. For example check the codes under number literals.

NSNumber Literals


       We use NSNumber class to wrap scaler(signed and unsigned short, char, int, long, long long, float, double, BOOL) values in Objective C Object. All scaler values also known as boxed values.

Lest go-ahead and create a method in "MOBJCViewController.m" as follows - 

- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    [self numberLiteral];
}

- (void)numberLiteral {
    NSNumber *n1 =@41; // equivalent to [NSNumber numberWithInteger:41];
    NSLog(@"Integer number = %i",[n1 integerValue]);
    
    NSNumber *n2 = @34.234; // equivalent to [NSNumber numberWithFloat:34.234];
    NSLog(@"Float number = %.2f",[n2 floatValue]);
    
    NSNumber *n3 = @31U; // equivalent to [NSNumber numberWithUnsignedInt:31U];
    NSLog(@"Unsigned Int = %u",[n3 unsignedIntegerValue]);
    
    NSNumber *n4 = @3456688876LL;//equivalent to [NSNumber numberWithLongLong:3456688876];
    NSLog(@"Long Long Value = %lld",[n4 longLongValue]);
       
}

      Now hit the run command and see the log in Xcode debug area -

LOG (Shift + Command + Y)
Integer number = 41
Float number = 34.23
Unsigned Int = 31
Long Long Value = 3456688876

In Modern Objective C any bool, char, numeric literal prefixed with '@' character will be evaluated to a pointer to an NSNumber object initialized with that value. Compiler will automatically take care of type of variable.

BOOL Literals


      Similar to number literals you don't need to use NSNumber class methods to convert BOOL values in number, just put '@' before YES and NO. Lets check in code, now create boolLiterals methods and call it from viewWillAppear: method as follows -

- (void)boolLiterals {
    NSNumber *numberYes = @YES;
    NSLog(@"value of numberYes = %d",[numberYes boolValue]);//1 means YES and Zero means NO
}

Check Xcode console, you will find 1 as value of 'numberYes'. Similarly you can create a number literal by assigning any character NSNumber *c = @'c';.
Note: NSNumber literals only support literal scalar values after the '@' that means you can write  @41, @YES, @'c' but not @INT_MIN because compiler translate your code as NSNumber *n1 = [NSNumber numberWithInteger: 41] and so-on .


Array Literals


           Array literals enable you to create NSArray in very less amount of code. No need to use the class methods to create the array. Array created using literal are immutable(you can not add or remove items from resulting array). Lets write code to create an array of friend and say hello to all.
- (void)sayHelloToFriends:(NSArray*)friends {
    for (int i = 0; i<friends.count; i++) {
        NSLog(@"Hello %@!!",friends[i]);
    }
}

In modern objective c, you can acces a particular element without using objectAtIndex: method. If you have completed the above method then call it in viewWillAppear: method of view controller as follows.

- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
//is array literals supported by compiler?
#if __has_feature(objc_array_literals)
    //Cheers!! literals are supported
    //create array using literals 
    NSArray *friends = @[ @"Joe", @"Kevin", @"Amit", @"Deepthi" ];
    NSLog(@"Array is created using literal");
#else
    //literals are not supported use old method
    
    NSArray *friends = [NSArray arrayWithObjects:@"Joe", @"Kevin", @"Amit", @"Deepthi",nil];
    NSLog(@"Array is created using NSArray class method");
#endif
    
    //call sayHelloToFriends: method and pass array of friends 
    [self sayHelloToFriends:friends];
}


We are checking availability of array literals by "__has_feature" check. Now RUN the application and check the output in log -

OUTPUT
Array is created using literal
Hello Joe!!
Hello Kevin!!
Hello Amit!!
Hello Deepthi!!

HOW ITS WORK?
When you create number or array using literals then compiler generates code for you. Compiler will generate following code for above array -

 //first holds your all items
 id objects[] = {@"Joe", @"Kevin", @"Amit", @"Deepthi"};
 //calculate number of items
 NSUInteger count = sizeof(objects)/ sizeof(id);
 //create array using class method
 friends = [NSArray arrayWithObjects:objects count:count];


Dictionary Literals


       Personally I love dictionary literals because it simplifies the the process of creating a dictionary and code is easy to understand and read. Lets create a dictionary using literals-

- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    //create a dictionary @{key:object, key:object}
    
    NSDictionary *person = @{
    @"name"     : @"Mithilesh Kumar",
    @"age"      : @22,
    @"email"    : @"talkmithilesh123@gmail.com",
    };

    [self printDictionary:person];
}

- (void)printDictionary:(NSDictionary*)dictionary {
    // Person details
    NSLog(@"NAME : %@",[dictionary objectForKey:@"name"]);
    NSLog(@"AGE : %d",[dictionary[@"age"] integerValue]);
    NSLog(@"EMAIL : %@",[dictionary objectForKey:@"email"]);
}

Have you notice the new way to access object from dictionary [dictionary[@"age"] integerValue] Yes!! you can access the object without using instance method objectForKey: .

NOTES: All container created using literals are immutable and you can not create constant using literals  static NSArray *arr = @[]; compiler will generates error. If you want to create constant using literals, use +(void)initialize  class method.

Object Subscripting


        Any Objective - C object can be used with subscript ( [ ] ) operator. By default objective C compiler support subscripting for NSArray and NSDictionary for example -

    NSMutableArray *array = [NSMutableArray arrayWithObjects:@"First",@"Second", nil];
    NSUInteger idx = @2;
    id newObject = @"New-Second";
    id oldObject = array[idx];
    array[idx] = newObject;         // replace oldObject with newObject
    
    NSArray *keys = @[@"one", @"two"];
    NSArray *values = @[@"First", @"Second"];
    NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithObjects:values forKeys:keys];
    NSString *key = @"two";
    oldObject = dictionary[key];
    dictionary[key] = newObject;    // replace oldObject with newObject


You can introduce subscripting in your objects by  implementing following four methods-
  1. - (id)objectAtIndexdSubscript:(NSUInteger)idx
  2. - (void)setObject:(id)object atIndexedSubscript:(NSUInteger)idx 
  3. - (id)objectForKeyedSubscript:(NSUInteger)idx
  4. - (void)setObject:(id)object forKeyedSubscript:(NSUInteger)idx
First two (1 and 2) are used for Array Style Subscripting and last two (3 and 4) are used for Dictionary Style Subscripting. You can implement any set of methods as your requirement. Actually when we use subscripts with array or dictionary objects then compiler translate that in above methods calls. For Example NSArray only implement - (id)objectAtIndexdSubscript:(NSUInteger)idx. Lets write a simple SongList class to see the Array Style subscripting -  

Add a class (Subclass of NSObject) and replace the code by following code

SongList.h

#import < Foundation/Foundation.h >
#import "Song.h"

@interface SongList : NSObject {
    NSMutableArray *list;
}

- (Song*)objectAtIndexedSubscript:(NSUInteger)idx;
- (void)setObject:(Song*)song atIndexedSubscript:(NSUInteger)idx;

@end


SongList.m

#import "SongList.h"

@implementation SongList

- (id)init
{
    self = [super init];
    if (self) {
        list = [[NSMutableArray alloc] init];
    }
    return self;
}

- (Song*)objectAtIndexedSubscript:(NSUInteger)idx {
    return ((Song*)list[idx]);
}
- (void)setObject:(Song*)song atIndexedSubscript:(NSUInteger)idx {
    list[idx] = song;
}
@end

To test the above code first create a "Song" class with a property called "name" and then import both these classes in viewController class and then replace the viewDidLoad: method and check the log -

- (void)viewDidLoad
{
    [super viewDidLoad];
 
    SongList *sList = [[SongList alloc] init];
    Song *s1 = [[Song alloc] init];
    s1.name = @"song - 1 ";
    sList[0] = s1;
    
    NSLog(@"Song Name is %@",sList[0].name);
    
}



Migrating To Modern Objective - C


        You can migrate your old projects to Modern Objective - C syntax by using Xcode refactor  tool as follows -
  1. Go to Edit menu
  2. Go to Refactor 
  3. Click on Convert to Modern Objective - C Syntax...
  4. Follow on screen instructions
Hey Cheers!! now you have completed almost  every thing related to Modern Objective C. Following table lists all required tools and backward compatibility of Modern Objective C's features - 

compatibility list
You can check updated list here
Hey Guys Thanks for reading!! Please don not forget to leave your valuable comments. Bye Bye !!