Objective C Coding Standards - paulmoore/AstroCalendar GitHub Wiki

Objective-C Coding Standards

Purpose

The purpose of this page is to provide guidelines for programmers as to how they should format their Objective-C code when contributing to the AstroCalendar project. Code that is written in a clear, concise, and consistent way is easier to read and modify. If the standard is followed, the entire code base should look as if it was written by a single programmer.

File Headers

Each source file should have a comment block with the following information:

  1. The file name.
  2. The project name.
  3. The Author and creation date of the file.
  4. Any relevant copyright information.
  5. The project homepage.
  6. The License header.

Below is an example of a file header. It is possible to setup Xcode to automatically insert a file header whenever you create a new file.

//
//  AstroCalendarAppDelegate.m
//  AstroCalendar
//
//  Created by Paul Moore on 11-10-19.
//  Copyright (c) 2011 University of British Columbia. All rights reserved.
//  https://github.com/paulmoore/AstroCalendar
/*
 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation
 files (the "Software"), to deal in the Software without
 restriction, including without limitation the rights to use,
 copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the
 Software is furnished to do so, subject to the following
 conditions:
 
 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */

Comments

Comments are vitally important to any project, especially when you have multiple developers working on the same code base.

Single Line Comments

Single line comments should be used when a single line of text is sufficient to comment a section of code within a function or method. Comments of this nature should typically describe 'why' or 'how' you did something. 'What' you did should be obvious from your code, if not, you should refactor it. The exception to this is when you are learning a new language or architecture (which is the case for this project), in which it is acceptable to leave comments on what a piece of code is meant to do.

Comments of this kind should are denoted by two forward slashes (//). The first slash should be indented with the next line of code, and a space should appear after the following slash, before the comment itself. These comments should be full, properly punctuated sentences. Comments should also not be located on the same line as a line of code or appear to interrupt a code block.

// This is a good comment.  This method makes myObject do something.
[myObject doSomething];

    //bad comment
[myObject doSomething]; // Another bad comment.

// The next comment is especially bad.
[myObject doSomethingElse];//doSomething];

if (index == 1)
// bad
{
    [myObject doSomething];
}

Multi-line Comments

Multi-line comments should only be used when a comment is large enough that it warrants more than one line to describe.

Such comments are denoted denoted by a single forward slash and an asterix and is closed by an asterix and a forward slash (/* */). These comments should follow the same rules as a single line comment, except a newline should be placed before and after the opening and closing tags. The tags should be indented the same as the comment text itself.

/*
This is a good comment.
It is potentially really big,
and needs multiple lines.
*/
[myObject doSomething];

/* a bad comment */

/*
   Another bad
   Multi-line comment.
*/

Doxygen Comments

Doxygen is a tool (similar to Javadoc) that can parse Objective-C comments (and other languages) into neat looking HTML pages. This is really handy for developers wishing to use source code without having to dig through the code itself to figure out how to do it.

Like Javadoc, Doxygen uses the same style of comments, a forward slash followed by two asterix's (/**) and is closed the same way as a multi-line comment (*/). All methods and properties of a class or protocol should be documented in the header file (.h) and not in the implementation file (.m).

There are many tags that can be used inside of a Doxygen comment, but the most important ones are: @param and @return. All methods that take parameters or have a non-void return value should include those tags respectively. In addition, all comments should include at a minimum a description, with the exception being trivial methods such as getters and setters (in which case, @return and @param tags are only required).

Below is an example of how to properly document a class or protocol. Note the extra asterix placed before each line of text.

/**
 * This class is the Application's Delegate.  It handles the initialization of the root view controller,
 * as well as setting up the window, etc.
 */
@interface AstroCalendarAppDelegate : UIResponder <UIApplicationDelegate, UINavigationControllerDelegate>

...

Below is an example of commenting a class's property. Note the comment may be placed on a single line.

/** The Navigation Controller object which is the root of the view heirarchy. */
@property (strong, nonatomic) UINavigationController *navController;

Below is an example of commenting a method with two parameters and a return value.

/**
 * The description of the method should go here.
 * Leave a blank space after the description.
 *
 * @param x The x parameter's description goes here.
 * @param y The y parameter's description goes here.
 * @return Returns a value which should be described here.
 */
- (int)doSomethingWithX:(int)x andY:(int)y;

Class and Protocol Declarations

Class Interfaces

A Class declaration comprises of two parts: The Interface and the Implementation. A file which contains a class interface should be located in a separate file from the implementation and have the header extension (.h).

The Following is a list of items in a class interface:

  1. The @interface tag.
  2. The name of the class.
  3. The class category, surrounded in parentheses.
  4. The name of the superclass, preceded by a colon.
  5. A Comma separated list of protocols this class follows, surrounded by angle brackets.

Additionally, an Interface may need to import certain files if it references other classes. This can be done by adding an import statement or using the @class tag. For user-defined classes, the @class tag is preferred. Note, the @class tag can be used if the compile only needs to know that some class exists, and not what methods and properties it has.

Below is an example of a Class Interface:

#import <ALibraryPath/LibraryHeaderFile.h>

#import "MyPath/MyHeaderFile.h"
#import "MyOtherHeaderFile.h"

@class SomeOtherClass;

@interface MyClass (MyCategory) : MySuperClass <MyProtocol1, MyProtocol2, MyProtocol3>
{
    // Class instance variables.
}

// Property declarations.  Note 'strong' and 'monatomic' are just examples of property properties.
@property (strong, nonatomic) MyPropertyType *myProperty;

// Class and instance methods.

@end

A Class Interface should be declared using the above template (minus the comments, of course). Note the spacing and brace placement. When using an #import statement, it is convention to use angle brackets to denote library packages, such as <UIKit/UIKit.h>. Double quotes are, also as a convention, used to denote user-defined header files. Either work in any case, but the convention should be followed. The path of an import is relative, and can be omitted if not needed.

If the class does not conform to any protocols, the angle brackets should be omitted. Similarly, the parentheses should be removed if the class does not have a Category.

IMPORTANT: do not use the #include directive! The #import directive offers the same functionality but also protects against a file from getting included more than once, and is thus more safe.

Class Implementations

A Class Implementation, as it suggests, implements all the methods and protocol methods declared in the Interface. An Implementation should be located in a separate file with the extension .m.

Below is an example of a Class Implementation:

// Imports.

// Required!
#import "MyClass.h"

@implementation MyClass

// Synthesized properties.
@synthesize myProperty;

// Class and instance methods.

@end

As you can see, you don't need to re-declare things such as superclass, category, or protocols, as they are already defined in the Interface.

Protocols

A Protocol in Objective-C is similar to an Interface in Java. A Protocol may declare required an optional methods for a Class to implement, and may itself be comprised of other Protocols. To create a Protocol requires only one file, named appropriately and with the header extension (.h).

Below is an example of a Protocol declaration:

@protocol MyProtocol <AnotherProtocol, AnothererProtocol>

@required
// Required methods

@optional
// Optional methods

@end

If no optional methods exist, the @required and @optional tags should be omitted (as the default is required). If the protocol does not inherit from any other protocols, the angle brackets should also be removed. As with a class Interface, the #import and @protocol (not @class) directives can be used to reference other Protocols that may be used in a Protocol's declaration.

Method Declaration and Implementations

Method Declaration

A method in Objective-C must be first declared in the Class's Interface. Below we see an example of declaring a method.

- (void)myMethod;

That method takes no parameters, and returns void. Notice the minus sign, this indicates the method belongs to an instance of the Class (think of a non-static Java method). Conversely, if the method has a plus sign (+) instead of a minus sign (-), the method belongs to the Class itself (think of a static Java method). As per the standard, notice the space placement.

Below we have a more complicated method. This is an actual method in AstroCalendar to make the meanings more clear.

- (id)initWithNavController:(UINavigationController *)controller andIsEndDate:(BOOL)isEndDate;

Note how every parameter can have a label in addition to it's name. This makes method calls easier to understand because the labels are present during a message.

// Easier to follow.
[[AstroCalendarSelectDateViewController alloc] initWithNavController:myController andIsEndDate:YES];

// Not as easy to understand.
[[AstroCalendarSelectDateViewController alloc] init:myController :YES];

While labels can be omitted, they are required for this standard (for clarity reasons). Also for the standard, there should only be a space after the +/- sign and after each parameter. The exception is when one of the parameters is a pointer, in which case a space should go before the asterix. This is to mimic the style in which a pointer is declared.

// As a variable.
UINavigationController *controller;

// As a parameter.
(UINavigationController *)controller

Method Implementation

The implementation of a method is placed in the Implementation file of the implementing Class. Its method signature remains exactly the same, the only difference is a pair of curly braces instead of the semi-colon indicating the method body.

- (id)initWithNavController:(UINavigationController *)controller andIsEndDate:(BOOL)isEndDate
{
    // Method implementation goes here.
}

Note the placement of the braces (they are wrapped, not Sun-style!) and the indentation after the brace, this is part of the standard.