So you want to write some code for WordPress for iOS. That’s nice, thanks a lot. But before that take some minutes to read some tips that will probably make everyone’s life easier.

Coding Style

In general, any third party library doesn’t need to comply with this style guide, and new code there must follow the library’s own style (since we want to send patches to the author)

General guidelines

Read Coding Guidelines for Cocoa from Apple

Interface Files

The interface files should be as small as possible and serve as a reference for what the class does and how to interact with it

  • System imports go before project imports
  • Don’t import anything that’s not needed for defining the interface
  • Only expose the minimum necessary for other classes to interact. Everything else goes into implementation file
  • Comment any non-obvious method
// MyClass.h
#import <SystemStuff.h>
#import "MyOtherClass.h"

@interface MyClass : NSObject <MyProtocol>

@property (nonatomic, retain) MyOtherClass *blog;
@property (nonatomic, readonly, retain) NSArray *readonlyThing;
@property (nonatomic, assign) id<MyClassDelegate> delegate;

/**
  Does stuff with the things
*/
- (void)doStuff;
@end

Implementation Files

  • If the interface file has declared readonly properties, redeclare them as readwrite to be able to use the accessors
  • Declare any internal variable and methods in the implementation
  • dealloc is the first method, followed by initialization methods
  • Feel free to use “#pragma mark -” to group methods into sections
// MyClass.m

#import "MyClass.h"
#import "MyClassHelper.h"

@interface MyClass ()
@property (nonatomic, retain) NSArray *readonlyThing;
- (void)prepareStuff;
@end

@implementation MyClass {
    NSMutableArray *_things;
    BOOL _flag;
}

@synthesize blog = _blog;
@synthesize delegate = _delegate;
@synthesize readonlyThing = _readonlyThing;

- (void)dealloc {
    [super dealloc];
    self.blog = nil;
    self.readonlyThing = nil;
    [_things release];
    // ...
}

- (void)init {
    self = [super init];
    if (self) {
        // Initialize
        _things = [[NSMutableArray alloc] init];
    }
    return self;
}

#pragma mark - Public methods

- (void)doStuff {
    [self prepareStuff];
    // Do actual stuff
}

#pragma mark - Private methods

- (void)prepareStuff {
    // Prepare stuff
    // self.readonlyThing = ...
}

@end

Before you commit

Besides the following guidelines, here’s a checklist before you commit:

  • Review what you commit: make sure you’re not leaving out anything, and that everything that you commit is meant to be there. You can use Xcode4 SVN interface (File > Source Control > Commit…), svn diff/status, git-svn + gitx, or any other GUI/tool. Just be sure what’s going into SVN.
  • Check for whitespace. Not the most critical thing, but if you follow the previous step, you might see unnecessary white space added at the end of a line. Get rid of it
  • No NSLog in commits. We all use NSLog (or our WP* FileLogger variants) to debug. Unless you really want that to be on production, and logged into the wordpress.log file, remove it before commit. Our app is verbose enough already.
  • No commented out code. If the code was already there and you’re removing it to test something, don’t comment it, just remove it. You can always go back by checking out a previous version from SVN.

If there’s a ticket associated, make sure to use “refs #123″ or “fixes #123″ in the commit message. It makes easier to track why things changed

Concurrency and background tasks

Usually, there are two cases when we need to use a background task: networking, and data processing tasks.

Networking is handled with AFNetworking in 3.0, which always executes callback blocks on the main thread/queue. More details to come.

Other background tasks could be: resizing/saving an image or video, cleaning temporary directories, or base64 encoding/decoding (although the last is usually part of a network call).

Starting with WordPress for iOS 3.0, performSelectorInBackground:withObject: and its counterpart performSelectorOnMainThread:withObject:waitUntilDone: are no longer welcome.

When possible, use GCD. Example:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
    // Do stuff in background...
    
    dispatch_async(dispatch_get_main_queue(), ^(void) {
        // Do stuff in main thread
    });
});

Avoid new compiler warnings

A compiler warning might seem harmless, but when we compile for the app store, we use -Werror, so those insignificant warnings turn into real errors and force us to investigate what’s wrong at the last minute. You really don’t want to be messing with the code at that point.