When Apple released the AppStore in 2008, it began a revolution that led to the largest and most vibrant application ecosystem in existence. Objective-C, the programming language for writing apps for Mac OS and iOS, went on to become the third most popular language of modern time after C and Java.
Objective-C has evolved considerably and we have features such as blocks, literals, subscripting, ARC etc. In a span of 3 years, so much of how we program has changed for the better. This article points out some of these new features.
Literals are shorthand notation of writing fixed values. Until recently, Objective-C only had literals for NSString.
// NSString literal NSString *string = @"Hello"; // The old and redundant way NSString *string = [NSString stringWithString:@"Hello"];
With Apple LLVM 4.0 onwards, literals for NSArray, NSDictionary and NSNumber were introduced. The following is the old way of writing code:
NSNumber *trueNumber = [NSNumber numberWithBOOL:YES]; NSArray *fruits = [NSArray arrayWithObjects:@"Apple", @"Papaya", @"Mango", @"Guava", nil]; NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:@"Brad", @"firstName", @"Pitt", @"lastName", nil]; NSNumber *magicNumber = [NSNumber numberWithUnsignedInt:25U];
With literals, the same code can be written as follows:
NSNumber *trueNumber = @(YES); NSArray *fruits = @[@"Apple", @"Papaya", @"Mango", @"Guava"]; NSDictionary *params = @{@"firstName" : @"Brad", @"lastName" : @"Pitt"}; NSNumber *magicNumber = @25U;
Literals are aimed at developers’ happiness and promote readability.
iOS development currently only supports manual memory management. All the projects written prior to LLVM 3.0 were manual memory managed i.e., a developer had to handle memory management manually by calling retain/copy/release/autorelease, following Apple’s Cocoa memory management guidelines. Though the rules were simple, new developers often fell prey to mistakes caused by manual memory management resulting in application crashes. To make things easier, Apple introduced Xcode 4.2 with LLVM 3.0 compiler supporting ARC.
According to Apple’s documentation: Automatic Reference Counting (ARC) is a compiler-level feature that simplifies the process of managing object lifetimes (memory management in Cocoa applications). ARC is a compiler generated step that adds retain/release/autorelease statements invisibly to the code for the developer. The following is an example written using the manual memory management environment:
// Create a user object PTUser *user = [[PTUser alloc] initWithDictionary:userDictionary]; // Do something awesome here // Release it when you are done [user release];
Under ARC, the same code would be:
// Create a user object PTUser *user = [[PTUser alloc] initWithDictionary:userDictionary]; // Do something awesome here // Release is not required as the compiler auto-adds this step invisibly to the user. // [user release];
While long time developers may still vouch for manual memory management, ARC keeps things simpler for beginners and is probably the way of the future.
Xcode 4.4 was released with Apple LLVM 4.0; it introduced default property synthesis. All the properties that are not @dynamic and do not have a custom getter / setter defined, are now automatically synthesized by default.
For example, have a look at code written using Apple LLVM 3.0 compiler and earlier.
@interface PTUser : NSObject @property (strong, nonatomic) NSNumber *userId; @property (strong, nonatomic) NSString *username; @property (strong, nonatomic) NSString *email; @end @implementation PTUser @synthesize userId = _userId; @synthesize username = _username; @synthesize email = _email; @end
The same code written using LLVM 4.0 and above with Default property synthesis would look like this:
@interface PTUser : NSObject @property (strong, nonatomic) NSNumber *userId; @property (strong, nonatomic) NSString *username; @property (strong, nonatomic) NSString *email; @end @implementation PTUser @end
This not only saves developer time, but also reduces the number of redundant lines of code.
iOS 4.0 introduced blocks, a language-level feature added to C, C++ and Objective-C. Blocks are like functions, but written inline with the rest of your code, inside other functions. They are sometimes called closures or lambdas in other languages.
^{ NSLog(@"Executing a block"); }
Blocks are handy in wrapping up a piece of code and effectively storing it for later use. In other words, blocks are excellent for handling callbacks and also acting as inline methods.
A traditional C callback example:
#include void callMeBack(void (*func)(void *), void *context) { func(context); } void callback(void *context) { int val = *(int *)context; printf("%d\n", val); } int main() { int val = 5; callMeBack(callback, &val); return 0; }
If you look at it, a developer has to think hard to understand the flow in which the code is executed. If you implement the same thing in blocks, it looks like this:
#include void callMeBlock(void (^block)(void)) { block(); } int main() { int val = 5; callMeBlock(^{ printf("%d\n", val); }); return 0; }
If you look at the above example, all the context-related arguments have disappeared. Using a block, we have been able to increase cohesion by moving code to where it belongs, making it easier for a developer to understand. Let’s take a look at other example.
Prior to blocks, we used to write it the following way:
- (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; } - (void)keyboardWillShow:(NSNotification *)notification { // Do something when the keyboard is shown }
With blocks, you can implement the same thing as:
- (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { // Do something when the keyboard is shown }]; }
Blocks have been added to all the newer APIs and offer the same level of syntactic sugar to the developers.
In UIKit
[self dismissViewControllerAnimated:YES completion:^{ [[NSNotificationCenter defaultCenter] postNotificationName:@"downloadCompleted" object:nil userInfo:nil]; }];
In Foundation
[[NSOperationQueue mainQueue] addOperationWithBlock:^{ [downloadHistory addObject:imagePath]; }];
In collection classes
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"Object at index %lu is %@", idx, obj); }];
iOS 4.0 also introduced Grand Central Dispatch (GCD), also known as libdispatch. GCD, with the help of blocks, allows developers to write concurrent code. We will cover GCD in an upcoming article very soon. Stay tuned.
Prior to storyboarding, User Interface design was primarily done using Interface Builder’s nibs/xibs. While nibs are nifty, Apple decided to tweak the current workflow of designing apps and introduced storyboarding to the developers with Xcode 4.2.
A storyboard is composed of a sequence of scenes, each of which represents a view controller and its views; scenes are connected by segue objects, which represent a transition between two view controllers.
Storyboarding helps developers visualize the appearance, navigational flow and transitions between scenes of the entire application under one canvas. On top of that, Xcode’s already powerful visual editing tools makes it easier for developers to design, layout and add/remove controls to a scene on the fly.