A good programmer gets the job done. A great programmer gets the job done, the right way. I’ve been a programmer for more than a decade now and been writing Objective-C code for almost half a decade. Some of the coding guidelines I follow have been immensely useful to me and I guess will be useful to you too.

Before that, a brief background. I started my career doing Win 32 SDK/MFC programming. Delved a bit into Windows Device Driver Kit (DDK) and into C#.NET and Java. Most of my life was into Object-oriented programming languages that are more strongly (and statically) typed than Javascript or PHP (and during those good old days, neither Javascript, nor PHP were Object oriented).

When a great programmer writes code in a given language, he follows the principles in that language instead of enforcing principles from his favourite language. In short, don’t write “Java” like code in Objective-C and Objective-C like code in Javascript. For most of us, Objective-C was not our first programming language and I believe, most of today’s Objective-C programmers are like me. A succinct explanation would help you understand the differences and make you a better Objective-C programmer.

Types in Objective-C

First is typing. Typing can be static or dynamic depending on when type safety is enforced by the language/compiler. Typing can be strong or weak depending on if the compiler would allow implicit type conversions. Some languages implicitly convert strings to integers and vice versa. so 1 + 2 is 3 and “1” + “2” is “12” and 1 + “2a” is “12a”.

Objective-C is somewhere in between a strongly typed language like Java/C# and a weakly typed language like Javascript/PHP. Most of the type checking is implemented at runtime and Objective-C is a dynamically typed language.

For example,

var $i = 1;
$i = "Hello World"

is perfectly valid is PHP (or Javascript), It’s illegal in a strongly typed language like C#/Java.
Objective-C, as I said before, is somewhere in between. The compiler will warn you that you are trying to assign a incompatible pointer type.

It enforces type at compile time (at least warns) on most classes, but not collections. That means, in Objective-C, you will get a warning when you assign a NSString to a UIViewController object, but it’s perfectly fine to add a NSString and a UIViewController object into the same NSMutableArray.

However, you are free to override the warning by simply using a typecast.

  NSArray *a;
  a = (NSArray*) @"Hello";

Not that I’m advocating typecasts, get the point that, Objective-C is weakly typed, but not as weakly typed as Javascript or PHP. Java/C# on the other hand are strongly typed less dynamic than Objective-C. In Java, adding a non-compliant object to a collection class will be caught by the compiler if the compiler can reliably infer the type of the added object or the run time will throw a ClassCastException. No such thing in Objective-C.

When it comes to programming, there is no one best language. As a great programmer, you should NOT be a fan of a given type system. Embrace strong+static typing when you code in Java and appreciate the beauty of semi-strong + dynamic typing when you write Objective-C. Objective-C (and most C based languages) were invented for writing high performance software and the onus of type safety or checking the bounds of array indices is on you, the programmer and not the compiler.

So there comes our first rule. Never write Objective-C code that reads like code from a strongly typed language.

Naming conventions

Objective-C method names are verbose. Yes, you are reading it right. Objective-C is a verbose language. Method names are verbose and less imperative than C/C++ or even Java. For example,

-getCacheDirectory; should probably be named as -cacheDirectory.

-convertToJson should probably be named as -jsonValue

Tone down the level of imperativeness in your code. Embrace verbosity. While your favourite language, Ruby is succinct, Objective-C isn’t. Ruby is succinct, probably because most of the typing is done using a text editor that doesn’t do intelligent auto completes. Writing succinct method names or writing macros to introduce succinctness in your Objective-C code will only confuse other Objective-C programmers who are not familiar with your “other” programming language.

When in Rome, be a Roman. While writing Objective-C code, be an Objective-C programmer.

Subclassing

In almost any programming language, subclassing a framework provided class is perfectly allowed. But not in Objective-C. Most of the commonly used classes like NSArray, NSSet, NSDictionary are essentially clusters. Subclassing them is not advised unless you are planning to forward invocations or by implementing all of the primitive methods necessary.

In most traditional programming languages, you subclass a foundation class (like for instance, a NSArray) to either provide additional methods or to override existing methods or to customise appearance of a UI element. In Objective-C, you provided additional methods using a category extension. You override SDK provided implementation by swizzling the method and you use the appearance proxy protocol to customise appearance of a UI element.

Having said that, there are some classes that you commonly override. UIViewController, UITableViewController, UIControl are a few to name. Subclassing UIViewController is probably the best thing you can do to your app. Adding common functionalities becomes just so easy. In every app I do, I have a UIViewController subclass that has a bunch of common functionalities. All other view controllers that I use in the app inherit from this special view controller.

So, instead of

@interface MyAppFeaturedYouTubeVideosViewController : UIViewController

it would be

@interface MyAppFeaturedYouTubeVideosFeaturedViewController : MyAppViewController
@interface MyAppViewController : UIViewController

This common base class can be used to add common functionalities in future. I usually have the following methods in this super class.

-(UIView*) errorView;
-(UIView*) loadingView;
-(void) showLoadingAnimated:(BOOL) animated;
-(void) hideLoadingViewAnimated:(BOOL) animated;
-(void) showErrorViewAnimated:(BOOL) animated;
-(void) hideErrorViewAnimated:(BOOL) animated;

Implementation details below.

-(UIView*) errorView {
 
  return nil;
}
 
-(UIView*) loadingView {
 
  return nil;
}
 
-(void) showLoadingAnimated:(BOOL) animated {
 
  UIView *loadingView = [self loadingView];
  loadingView.alpha = 0.0f;
  [self.view addSubview:loadingView];
  [self.view bringSubviewToFront:loadingView];
 
  double duration = animated ? 0.4f:0.0f;
  [UIView animateWithDuration:duration animations:^{
    loadingView.alpha = 1.0f;
  }];
}
 
-(void) hideLoadingViewAnimated:(BOOL) animated {
 
  UIView *loadingView = [self loadingView];
 
  double duration = animated ? 0.4f:0.0f;
  [UIView animateWithDuration:duration animations:^{
    loadingView.alpha = 0.0f;
  } completion:^(BOOL finished) {
    [loadingView removeFromSuperview];
  }];
}
 
-(void) showErrorViewAnimated:(BOOL) animated {
 
  UIView *errorView = [self errorView];
  errorView.alpha = 0.0f;
  [self.view addSubview:errorView];
  [self.view bringSubviewToFront:errorView];
 
  double duration = animated ? 0.4f:0.0f;
  [UIView animateWithDuration:duration animations:^{
    errorView.alpha = 1.0f;
  }];
}
 
-(void) hideErrorViewAnimated:(BOOL) animated {
 
  UIView *errorView = [self errorView];
 
  double duration = animated ? 0.4f:0.0f;
  [UIView animateWithDuration:duration animations:^{
    errorView.alpha = 0.0f;
  } completion:^(BOOL finished) {
    [errorView removeFromSuperview];
  }];
}

Now, in my application’s View Controller subclass, I can easily change the view to a “loading” state or “error” state just by calling one of the following methods. Additionally, view controllers can override, -errorView and -loadingView methods to provide their own custom error and loading views.

You can even override viewDidLoad in the super class to change the look and feel of the all the views in your app. For example, adding a background pattern to your views or changing the background colour of all your views.

- (void)viewDidLoad
{
  [super viewDidLoad];
  self.view.backgroundColor = [UIColor appOffWhiteColor]; // changes all my views to "off-white"
}

UI Customisation

UI Customisation can be classified broadly into two. Writing custom controls. Skinning/theming the app. The former is what makes the app stand out from the crowd. The latter is what most apps require. I recommend writing a category extension on UIFont and UIColor to provide custom fonts and colours for your app.

For example, add methods like

+(UIFont*) appFontOfSize:(CGFloat) pointSize {
 
  return [UIFont fontWithName:@"MyriadPro-Regular" size:pointSize];
}
 
+(UIFont*) boldAppFontOfSize:(CGFloat) pointSize {
 
  return [UIFont fontWithName:@"MyriadPro-Black" size:pointSize];
}

to a UIFont category and use [UIFont appFontOfSize:13] to create a MyriadPro-Regular font. This way, you can easily switch to a different font later when your designer decides so.

The same design pattern can be applied for providing custom colours. Add a category on UIColor and write methods like the following

#define GREY(color) [UIColor colorWithRed:color/255.0 green:color/255.0 blue:color/255.0 alpha:1]
 
+(UIColor*) appBackgroundColor {
 
  return [UIColor colorWithPatternImage:[UIImage imageNamed:@"BGPattern"]];
}
 
+(UIColor*) appBlack1Color {
 
  return GREY(38);
}
 
+(UIColor*) appOffWhiteColor {
 
  return GREY(234);
}

For heavens’ sake, don’t use Interface Builder for choosing a colour.

Subclassing UILabels

There is one other school of thought where developers subclass UILabel, UITextField, UITextView and set the font and colour in the initWithFrame and initWithCoder methods. The following explains this technique.

@implementation AppPrefixLabel
 
-(void) setup {
 
  self.font = [UIFont fontWithName:@"SourceSansPro-Semibold" size:self.font.pointSize];
  self.textColor = [UIColor redColor];
}
 
-(id) initWithFrame:(CGRect)frame {
 
  if((self = [super initWithFrame:frame])) {
 
    [self setup];
  }
 
  return self;
}
-(id) initWithCoder:(NSCoder *)aDecoder {
 
  if((self = [super initWithCoder:aDecoder])) {
 
    [self setup];
  }
 
  return self;
}
 
@end

This technique allows developers to customise appearance of labels and other UIKit elements from Interface Builder. Drag a UILabel to your view and change the class of the label to your custom class, and boom! your fonts and colours are instantly applied without you having to write additional code.

While this technique works for most part, it becomes troublesome when your application supports custom themes and users can change themes from, say, a settings screen.

initWithFrame: and initWithCoder: are creation methods that are called once when the UI element is created and changing the font after it is created requires a bunch of boiler plate code. So, if your app supports themes, create a theme manager singleton that “provides” themes and colours for the entire project.

If you use the first method that I explained, your UIFont category extension methods will now be implemented as

+(UIFont*) appFontOfSize:(CGFloat) pointSize {
 
  NSString *currentFontName = [[ThemeProvider sharedInstance] currentFontName];
  return [UIFont fontWithName:currentFontName size:pointSize];
}

Same applies to UIColor category extension methods as well. There is no right or wrong ways to do this. Both methods are perfectly fine and I’ll leave it to you to figure out which works best for your app.

Following basic design patterns I explained here can make your iOS project look clean like a well written JS/CSS. Try it in your next app and let me know!


Mugunth

Follow me on Twitter

  • Hiệp Lê tuấn

    Thank you, Mugunth. This post is very usefull.

  • Javier Ernesto Flores Robles

    Good article but, lacks examples for subjectiveness reduction.

  • Alice Vieira

    Great! Thank you for sharing.

  • jxdwinterJiang

    This is awesome! Thank you!

  • TianBao Han

    Thanks,i try some .
    And i have a problem with SubClassing,
    when i use hideErrorView or hideLoadingView methods,i can’t remove errorView or loadingView from viewController,

    Could you give a demo for it?
    Thanks