└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # The Objective-C Style Guide for Wordpress Mobile apps 2 | 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. Much of this guide is adapted from [Google's Objective-C Style Guide](http://google.github.io/styleguide/objcguide.html). You should read that as well as [Apple's Coding Guidelines for Cocoa](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html). 3 | 4 | ## Before You Commit 5 | * Review what you commit: make sure you’re not leaving out anything, and that everything that you commit is meant to be there. `git add -p` is your friend here. 6 | * 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 7 | * 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. 8 | * 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 source control. 9 | * 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. 10 | 11 | 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 12 | 13 | ## Spacing and Formatting 14 | ### Spaces vs Tabs 15 | Use only spaces, and indent 4 spaces at a time. 16 | ### Line Length 17 | Each line of text in your code should try to be at most 100 characters long. Objective C is a fairly verbose language and occasionally it makes sense to extend past the 100 character limit. However, this should be a rare occurrence and not commonplace. 18 | ### Method Declarations and Definitions 19 | One space should be used between the - or + and the return type, and no spacing in the parameter list except between parameters. 20 | Methods should look like this: 21 | 22 | ```objective-c 23 | - (void)doSomethingWithString:(NSString *)theString 24 | { 25 | ... 26 | } 27 | ``` 28 | 29 | If you have more than one parameter, giving each its own line is preferred. If multiple lines are used, align each using the colon before the parameter. 30 | 31 | ```objective-c 32 | - (void)doSomethingWith:(GTMFoo *)theFoo 33 | rect:(NSRect)theRect 34 | interval:(float)theInterval 35 | { 36 | ... 37 | } 38 | ``` 39 | 40 | ### Method Invocations 41 | Method invocations should be formatted much like method declarations. When there's a choice of formatting styles, follow the convention already used in a given source file. 42 | Invocations should have all arguments on one line: 43 | ```objective-c 44 | [myObject doFooWith:arg1 name:arg2 error:arg3]; 45 | ``` 46 | or have one argument per line, with colons aligned: 47 | 48 | ```objective-c 49 | [myObject doFooWith:arg1 50 | name:arg2 51 | error:arg3]; 52 | ``` 53 | 54 | Don't use any of these styles: 55 | 56 | ```objective-c 57 | [myObject doFooWith:arg1 name:arg2 // some lines with >1 arg 58 | error:arg3]; 59 | 60 | [myObject doFooWith:arg1 61 | name:arg2 error:arg3]; 62 | 63 | [myObject doFooWith:arg1 64 | name:arg2 // aligning keywords instead of colons 65 | error:arg3]; 66 | ``` 67 | 68 | ### Protocols 69 | There should not be a space between the type identifier and the name of the protocol encased in angle brackets. 70 | This applies to class declarations, instance variables, and method declarations. For example: 71 | ```objective-c 72 | @interface MyProtocoledClass : NSObject { 73 | id _delegate; 74 | } 75 | - (void)setDelegate:(id)aDelegate; 76 | @end 77 | ``` 78 | 79 | ### Blocks 80 | Blocks are preferred to the target-selector pattern when creating callbacks, as it makes code easier to read. Code inside blocks should be indented four spaces. 81 | There are several appropriate style rules, depending on how long the block is: 82 | * If the block can fit on one line, no wrapping is necessary. 83 | * If it has to wrap, the closing brace should line up with the first character of the line on which the block is declared. 84 | * Code within the block should be indented four spaces. 85 | * If the block is large, e.g. more than 20 lines, it is recommended to move it out-of-line into a local variable. 86 | * If the block takes no parameters, there are no spaces between the characters ^{. If the block takes parameters, there is no space between the ^( characters, but there is one space between the ) { characters. 87 | * Two space indents inside blocks are also allowed, but should only be used when it's consistent with the rest of the project's code. 88 | 89 | ```objective-c 90 | // The entire block fits on one line. 91 | [operation setCompletionBlock:^{ [self onOperationDone]; }]; 92 | 93 | // The block can be put on a new line, indented four spaces, with the 94 | // closing brace aligned with the first character of the line on which 95 | // block was declared. 96 | [operation setCompletionBlock:^{ 97 | [self.delegate newDataAvailable]; 98 | }]; 99 | 100 | // Using a block with a C API follows the same alignment and spacing 101 | // rules as with Objective-C. 102 | dispatch_async(_fileIOQueue, ^{ 103 | NSString* path = [self sessionFilePath]; 104 | if (path) { 105 | // ... 106 | } 107 | }); 108 | 109 | // An example where the parameter wraps and the block declaration fits 110 | // on the same line. Note the spacing of |^(SessionWindow *window) {| 111 | // compared to |^{| above. 112 | [[SessionService sharedService] 113 | loadWindowWithCompletionBlock:^(SessionWindow *window) { 114 | if (window) { 115 | [self windowDidLoad:window]; 116 | } else { 117 | [self errorLoadingWindow]; 118 | } 119 | }]; 120 | 121 | // Large blocks can be declared out-of-line. 122 | void (^largeBlock)(void) = ^{ 123 | // ... 124 | }; 125 | [_operationQueue addOperationWithBlock:largeBlock]; 126 | ``` 127 | 128 | ### Braces 129 | 130 | When writing code that needs braces we generally want the brace on a new line rather than on the same line. The exception to this rule would be for if statements or for statements. 131 | ```objective-c 132 | // Bad 133 | - (void)someMethod { 134 | // Do something 135 | } 136 | 137 | // Good 138 | - (void)someMethod 139 | { 140 | // Do something 141 | } 142 | 143 | // Good 144 | if (condition) { 145 | // Do something 146 | } 147 | 148 | // Good 149 | for (int i=0; i < len; i++) { 150 | // Do something 151 | } 152 | ``` 153 | 154 | ### If Statements 155 | 156 | When writing if statements, make sure to use a curly brace even if it's a one line statement. Always put the opening curly brace on the same line as an if. The only exception to this rule is when the condition is long enough to need separating between multiple lines. Also make sure there is a space between the `if` and the opening parenthesis. 157 | ```objective-c 158 | // Good 159 | if (someValue != nil) { 160 | [self doSomething]; 161 | } 162 | 163 | // Good 164 | if (someReallyLongVariableName != nil 165 | && someOtherLongVariableName != nil) 166 | { 167 | [self doSomething]; 168 | } 169 | 170 | // Bad 171 | if (someValue != nil) 172 | [self doSomething]; 173 | ``` 174 | 175 | ### Ternary Operators 176 | 177 | Be cautious about using the ternary operator as it can make code very difficult to read. Only use a ternary operator if using it makes the code easier to read. 178 | 179 | ```objective-c 180 | 181 | // Good 182 | int minVal = (a < b) ? a : b 183 | 184 | // Bad 185 | [self.view addSubview:((currentlyVisibleView == self.photoSelectorView) ? self.textEditorView : self.photoSelectorView)]; 186 | 187 | ``` 188 | 189 | ### Multi Line Declarations 190 | 191 | Don't declare a series of variables on one line but rather split them up into individual lines. The reason for this is that splitting them into multiple lines makes the code easier to read and it makes diffs easier to analyze. 192 | 193 | ```objective-c 194 | 195 | // Bad 196 | @property (nonatomic, copy) NSString *username, *url, *password; 197 | 198 | // Good 199 | @property (nonatomic, copy) NSString *username; 200 | @property (nonatomic, copy) NSString *url; 201 | @property (nonatomic, copy) NSString *password; 202 | 203 | ``` 204 | 205 | ## Naming 206 | Naming rules are very important in maintainable code. Objective-C method names tend to be very long, but this has the benefit that a block of code can almost read like prose, thus rendering many comments unnecessary. 207 | 208 | When writing pure Objective-C code, we mostly follow standard [Objective-C naming rules](http://developer.apple.com/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html). 209 | 210 | Any class, category, method, or variable name may use all capitals for initialisms within the name. This follows Apple's standard of using all capitals within a name for initialisms such as URL, TIFF, and EXIF. An exception to this is when passing a URL as a _NSString_ we prefer to not to use all capitals. The reason for this is that a non all capitalized URL stands out as more obvious that the variable in question is a _NSString_ instead of a _NSURL_. 211 | 212 | ```objective-c 213 | - (void)displayWebsite:(NSURL *)websiteURL 214 | { 215 | ... 216 | } 217 | 218 | - (void)displayWebsite:(NSString *)websiteUrl 219 | { 220 | ... 221 | } 222 | ``` 223 | 224 | ### File Names 225 | File names should reflect the name of the class implementation that they contain—including case. 226 | 227 | File names for categories should include the name of the class being extended, e.g. _NSString+Helpers.h_ or _UIColors+Helpers.h_ 228 | 229 | ### Class Names 230 | Class names (along with category and protocol names) should start as uppercase and use mixed case to delimit words. 231 | 232 | In application-level code, prefixes on class names should generally be avoided. Having every single class with same prefix impairs readability for no benefit. When designing code to be shared across multiple applications, prefixes are acceptable and recommended (e.g. _WPXMLRPCEncoder_). 233 | 234 | ### Objective-C Method Names 235 | Method names should start as lowercase and then use mixed case. Each named parameter should also start as lowercase. 236 | The method name should read like a sentence if possible, meaning you should choose parameter names that flow with the method name. (e.g. _convertPoint:fromRect_: or _replaceCharactersInRange:withString:_). See [Apple's Guide to Naming Methods](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingMethods.html#//apple_ref/doc/uid/20001282-BCIGIJJF) for more details. 237 | 238 | Accessor methods should be named the same as the variable they're "getting", but they should not be prefixed with the word "get". For example: 239 | ```objective-c 240 | - (id)getDelegate; // AVOID 241 | - (id)delegate; // GOOD 242 | ``` 243 | 244 | ### Variable Names 245 | Variables names start with a lowercase and use mixed case to delimit words. Instance variables have leading underscores. For example: _myLocalVariable_, *_myInstanceVariable*. 246 | 247 | **Common Variable Names** 248 | 249 | Do not use Hungarian notation for syntactic attributes, such as the static type of a variable (int or pointer). Give as descriptive a name as possible, within reason. Don't worry about saving horizontal space as it is far more important to make your code immediately understandable by a new reader. For example: 250 | ```objective-c 251 | // Bad 252 | int w; 253 | int nerr; 254 | int nCompConns; 255 | tix = [[NSMutableArray alloc] init]; 256 | obj = [someObject object]; 257 | p = [network port]; 258 | 259 | // Good 260 | int numErrors; 261 | int numCompletedConnections; 262 | tickets = [[NSMutableArray alloc] init]; 263 | userInfo = [someObject object]; 264 | port = [network port]; 265 | ``` 266 | **Instance Variables** 267 | Instance variables are mixed case and should be prefixed with an underscore e.g. *_usernameTextField*. 268 | 269 | ### Comments 270 | Though a pain to write, they are absolutely vital to keeping our code readable. The following rules describe what you should comment and where. But remember: while comments are very important, the best code is self-documenting. Giving sensible names to types and variables is much better than using obscure names and then trying to explain them through comments. 271 | 272 | When writing your comments, write for your audience: the next contributor who will need to understand your code. Be generous—the next one may be you! 273 | 274 | **File Comments** 275 | A file may optionally start with a description of its contents. 276 | Every file should contain the following items, in order: 277 | * GPL License 278 | * a basic description of the contents of the file if necessary. 279 | 280 | If you make significant changes to a file with an author line, consider deleting the author line since revision history already provides a more detailed and accurate record of authorship. 281 | 282 | **Declaration Comments** 283 | Every interface, category, and protocol declaration should have an accompanying comment describing its purpose and how it fits into the larger picture. 284 | ```objective-c 285 | // A delegate for NSApplication to handle notifications about app 286 | // launch and shutdown. Owned by the main app controller. 287 | @interface MyAppDelegate : NSObject { 288 | ... 289 | } 290 | @end 291 | ``` 292 | If you have already described an interface in detail in the comments at the top of your file feel free to simply state "See comment at top of file for a complete description", but be sure to have some sort of comment. 293 | 294 | Additionally, each method in the public interface should have a comment explaining its function, arguments, return value, and any side effects. 295 | 296 | Document the synchronization assumptions the class makes, if any. If an instance of the class can be accessed by multiple threads, take extra care to document the rules and invariants surrounding multithreaded use. 297 | 298 | ## Cocoa and Objective-C Features 299 | ### Interface files 300 | 301 | Interface files should be as short as possible: don't declare instance variables, and declare only properties and methods that need to be exposed to other classes. Everything else should go into an interface extension inside the implementation file. Remember that you don't need to declare private methods anymore with a modern Xcode version. 302 | 303 | ### Overridden NSObject Method Placement 304 | It is strongly recommended and typical practice to place overridden methods of _NSObject_ at the top of an _@implementation_. This commonly applies (but is not limited) to the _init..._, _copyWithZone:_, and _dealloc_ methods. _init_... methods should be grouped together, followed by the _copyWithZone:_ method, and finally the _dealloc_ method. 305 | 306 | ### Initialization 307 | Don't initialize variables to _0_ or _nil_ in the init method; it's redundant. 308 | 309 | All memory for a newly allocated object is initialized to _0_ (except for isa), so don't clutter up the init method by re-initializing variables to _0_ or _nil_. 310 | 311 | ### Keep the Public API Simple 312 | Keep your class simple; avoid "kitchen-sink" APIs. If a method doesn't need to be public, don't make it so. 313 | 314 | ### Use Root Frameworks 315 | Include root frameworks over individual files. 316 | 317 | While it may seem tempting to include individual system headers from a framework such as Cocoa or Foundation, in fact it's less work on the compiler if you include the top-level root framework. The root framework is generally pre-compiled and can be loaded much more quickly. In addition, remember to use #import rather than #include for Objective-C frameworks. 318 | ```objective-c 319 | // good 320 | #import 321 | 322 | // avoid 323 | #import 324 | ... 325 | ``` 326 | 327 | ### Avoid Accessors During init and dealloc 328 | Instance subclasses may be in an inconsistent state during _init_ and _dealloc_ method execution, so code in those methods should avoid invoking accessors. 329 | 330 | Subclasses have not yet been initialized or have already deallocated when _init_ and _dealloc_ methods execute, making accessor methods potentially unreliable. Whenever practical, directly assign to and release ivars in those methods rather than rely on accessors. 331 | 332 | ```objective-c 333 | // Good 334 | 335 | - (id)init 336 | { 337 | self = [super init]; 338 | if (self) { 339 | _bar = [[NSMutableString alloc] init]; 340 | } 341 | return self; 342 | } 343 | 344 | - (void)dealloc 345 | { 346 | [_bar release]; 347 | [super dealloc]; 348 | } 349 | 350 | // Avoid 351 | 352 | - (id)init 353 | { 354 | self = [super init]; 355 | if (self) { 356 | self.bar = [NSMutableString string]; 357 | } 358 | return self; 359 | } 360 | 361 | - (void)dealloc 362 | { 363 | self.bar = nil; 364 | [super dealloc]; 365 | } 366 | ``` 367 | ### Setters copy NSStrings 368 | Setters taking an _NSString_, should always copy the string it accepts. 369 | 370 | Never just retain the string. This avoids the caller changing it under you without your knowledge. Don't assume that because you're accepting an _NSString_ that it's not actually an _NSMutableString_. 371 | 372 | ```objective-c 373 | - (void)setFoo:(NSString *)aFoo 374 | { 375 | [_foo autorelease]; 376 | _foo = [aFoo copy]; 377 | } 378 | ``` 379 | 380 | ### nil Checks 381 | Use _nil_ checks for logic flow only. 382 | 383 | Use _nil_ checks for logic flow of the application, not for crash prevention. Sending a message to a nil object is handled by the Objective-C runtime. If the method has no return result, you're good to go. However if there is one, there may be differences based on runtime architecture, return size, and OS X version (see Apple's documentation for specifics). 384 | 385 | ### BOOL Pitfalls 386 | Be careful when converting general integral values to _BOOL_. Avoid comparing directly with _YES_. 387 | 388 | _BOOL_ is defined as a signed char in Objective-C which means that it can have values other than _YES_ (1) and _NO_ (0). Do not cast or convert general integral values directly to _BOOL_. Common mistakes include casting or converting an array's size, a pointer value, or the result of a bitwise logic operation to a _BOOL_ which, depending on the value of the last byte of the integral result, could still result in a _NO_ value. When converting a general integral value to a _BOOL_ use ternary operators to return a _YES_ or _NO_ value. 389 | 390 | You can safely interchange and convert _BOOL_, *_Bool* and _bool_ (see C++ Std 4.7.4, 4.12 and C99 Std 6.3.1.2). You cannot safely interchange _BOOL_ and _Boolean_ so treat _Booleans_ as a general integral value as discussed above. Only use _BOOL_ in Objective C method signatures. 391 | 392 | Using logical operators (_&&_, _||_ and _!_) with _BOOL_ is also valid and will return values that can be safely converted to _BOOL_ without the need for a ternary operator. 393 | 394 | ```objective-c 395 | // Bad 396 | 397 | - (BOOL)isBold 398 | { 399 | return [self fontTraits] & NSFontBoldTrait; 400 | } 401 | - (BOOL)isValid 402 | { 403 | return [self stringValue]; 404 | } 405 | 406 | // Good 407 | - (BOOL)isBold 408 | { 409 | return ([self fontTraits] & NSFontBoldTrait) ? YES : NO; 410 | } 411 | - (BOOL)isValid 412 | { 413 | return [self stringValue] != nil; 414 | } 415 | - (BOOL)isEnabled 416 | { 417 | return [self isValid] && [self isBold]; 418 | } 419 | ``` 420 | Also, don't directly compare _BOOL_ variables directly with _YES_. Not only is it harder to read for those well-versed in C, the first point above demonstrates that return values may not always be what you expect. 421 | ```objective-c 422 | // Bad 423 | BOOL great = [foo isGreat]; 424 | if (great == YES) 425 | // ...be great! 426 | 427 | //Good 428 | BOOL great = [foo isGreat]; 429 | if (great) 430 | // ...be great! 431 | ``` 432 | ### Properties 433 | Use of the _@property_ directive is preferred. Dot notation is allowed only for access to a declared @property. 434 | 435 | Use of automatically synthesized instance variables is preferred. 436 | 437 | **Location** 438 | 439 | A property's declaration must come immediately after the instance variable block of a class interface. A property's definition (if not using automatic synthesis) must come immediately after the _@implementation_ block in a class definition. They are indented at the same level as the _@interface_ or _@implementation_ statements that they are enclosed in. 440 | ```objective-c 441 | @interface MyClass : NSObject 442 | @property(copy, nonatomic) NSString *name; 443 | @end 444 | 445 | @implementation MyClass 446 | 447 | - (id)init 448 | { 449 | ... 450 | } 451 | @end 452 | ``` 453 | **Use Copy Attribute For Strings** 454 | NSString properties should always be declared with the _copy_ attribute. 455 | 456 | This logically follows from the requirement that setters for NSStrings always must use _copy_ instead of _retain_. 457 | 458 | **Dot notation** 459 | Dot notation is idiomatic style for Objective-C 2.0. It may be used when doing simple operations to get and set a _@property_ of an object, but should not be used to invoke other object behavior. 460 | ```objective-c 461 | // Good 462 | NSString *oldName = myObject.name; 463 | myObject.name = @"Alice"; 464 | NSArray *array = [[NSArray arrayWithObject:@"hello"] retain]; 465 | 466 | // Bad 467 | NSUInteger numberOfItems = array.count; // not a property 468 | array.release; // not a property 469 | ``` 470 | ### Interfaces Without Instance Variables 471 | Omit the empty set of braces on interfaces that do not declare any instance variables. 472 | ```objective-c 473 | // Good 474 | @interface MyClass : NSObject 475 | // Does a lot of stuff 476 | - (void)fooBarBam; 477 | @end 478 | 479 | // Bad 480 | @interface MyClass : NSObject { 481 | } 482 | // Does a lot of stuff 483 | - (void)fooBarBam; 484 | @end 485 | ``` 486 | 487 | ### NSNumber, NSArray and NSDictionary Literals 488 | For projects that use Xcode 4.4 or later with clang, the use of NSNumber, NSArray and NSDictionary [literals](http://clang.llvm.org/docs/ObjectiveCLiterals.html) is allowed and preferred. 489 | 490 | NSNumber literals are used just like Objective C string literals. Boxing is used when necessary. 491 | ```objective-c 492 | // NSNumber 493 | NSNumber *fortyTwo = @42; 494 | NSNumber *piOverTwo = @(M_PI / 2); 495 | typedef NS_ENUM(NSUInteger, MyEnum) { 496 | MyEnumOne, 497 | MyEnumTwo = 2, 498 | }; 499 | NSNumber *myEnum = @(MyEnumTwo); 500 | 501 | // NSArray 502 | NSArray *continents = @[@"North America", @"South America", @"Europe", @"Asia", @"Africa", @"Antarctica", @"Australia"]; 503 | 504 | // NSDictionary 505 | NSDictionary *personInfo = @{ @"name" : @"John Doe", @"age" : @(25) }; 506 | ``` 507 | 508 | ### Constant definitions 509 | 510 | Avoid using `#define` for constants, they should be defined using `const`. Constant names should start with an uppercase letter and use mixed case. 511 | 512 | ```objective-c 513 | // Good 514 | NSInteger const ReaderPostsToSync = 20; 515 | NSString *const ReaderLastSyncDateKey = @"ReaderLastSyncDate"; 516 | 517 | // Bad 518 | #define READER_POSTS_TO_SYNC 20; 519 | #define READER_SYNC_DATE_KEY @"ReaderLastSyncDate"; 520 | ``` 521 | 522 | Constants should be defined in the implementation file. If a class needs to expose a constant, it should be defined as `extern` on the interface file, then initialised in the implementation file: 523 | 524 | ```objective-c 525 | // Blog+Jetpack.h 526 | extern NSString * const BlogJetpackErrorDomain; 527 | 528 | // Blog+Jetpack.m 529 | NSString * const BlogJetpackErrorDomain = @"BlogJetpackError"; 530 | ``` --------------------------------------------------------------------------------