{"id":20187478,"url":"https://github.com/wordpress-mobile/objective-c-style-guide","last_synced_at":"2025-03-03T07:11:31.440Z","repository":{"id":56648116,"uuid":"44337174","full_name":"wordpress-mobile/objective-c-style-guide","owner":"wordpress-mobile","description":"Objective-C Style Guide","archived":false,"fork":false,"pushed_at":"2020-10-27T09:47:33.000Z","size":12,"stargazers_count":12,"open_issues_count":0,"forks_count":6,"subscribers_count":4,"default_branch":"trunk","last_synced_at":"2025-01-13T18:23:09.966Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wordpress-mobile.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-10-15T18:28:35.000Z","updated_at":"2024-05-01T11:15:59.000Z","dependencies_parsed_at":"2022-08-15T22:31:42.381Z","dependency_job_id":null,"html_url":"https://github.com/wordpress-mobile/objective-c-style-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wordpress-mobile%2Fobjective-c-style-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wordpress-mobile%2Fobjective-c-style-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wordpress-mobile%2Fobjective-c-style-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wordpress-mobile%2Fobjective-c-style-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wordpress-mobile","download_url":"https://codeload.github.com/wordpress-mobile/objective-c-style-guide/tar.gz/refs/heads/trunk","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241622613,"owners_count":19992504,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T03:24:16.396Z","updated_at":"2025-03-03T07:11:31.402Z","avatar_url":"https://github.com/wordpress-mobile.png","language":null,"readme":"# The Objective-C Style Guide for Wordpress Mobile apps\nSo 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).\n\n## Before You Commit\n* 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.\n* 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\n* 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.\n* 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.\n* 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.\n\nIf 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\n\n## Spacing and Formatting\n### Spaces vs Tabs\nUse only spaces, and indent 4 spaces at a time.\n### Line Length\nEach 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.\n### Method Declarations and Definitions\nOne space should be used between the - or + and the return type, and no spacing in the parameter list except between parameters.\nMethods should look like this:\n\n```objective-c\n- (void)doSomethingWithString:(NSString *)theString\n{\n    ...\n}\n```\n\nIf 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.\n\n```objective-c\n- (void)doSomethingWith:(GTMFoo *)theFoo\n                   rect:(NSRect)theRect\n               interval:(float)theInterval\n{\n    ...\n}\n```\n\n### Method Invocations\nMethod 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.\nInvocations should have all arguments on one line:\n```objective-c\n[myObject doFooWith:arg1 name:arg2 error:arg3];\n```\nor have one argument per line, with colons aligned:\n\n```objective-c\n[myObject doFooWith:arg1\n               name:arg2\n              error:arg3];\n```\n\nDon't use any of these styles:\n\n```objective-c\n[myObject doFooWith:arg1 name:arg2  // some lines with \u003e1 arg\n              error:arg3];\n\n[myObject doFooWith:arg1\n               name:arg2 error:arg3];\n\n[myObject doFooWith:arg1\n          name:arg2  // aligning keywords instead of colons\n          error:arg3];\n```\n\n### Protocols\nThere should not be a space between the type identifier and the name of the protocol encased in angle brackets.\nThis applies to class declarations, instance variables, and method declarations. For example:\n```objective-c\n@interface MyProtocoledClass : NSObject\u003cNSWindowDelegate\u003e {\n    id\u003cMyFancyDelegate\u003e _delegate;\n}\n- (void)setDelegate:(id\u003cMyFancyDelegate\u003e)aDelegate;\n@end\n```\n\n### Blocks\nBlocks 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.\nThere are several appropriate style rules, depending on how long the block is:\n* If the block can fit on one line, no wrapping is necessary.\n* If it has to wrap, the closing brace should line up with the first character of the line on which the block is declared.\n* Code within the block should be indented four spaces.\n* If the block is large, e.g. more than 20 lines, it is recommended to move it out-of-line into a local variable.\n* 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.\n* 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.\n\n```objective-c\n// The entire block fits on one line.\n[operation setCompletionBlock:^{ [self onOperationDone]; }];\n\n// The block can be put on a new line, indented four spaces, with the\n// closing brace aligned with the first character of the line on which\n// block was declared.\n[operation setCompletionBlock:^{\n    [self.delegate newDataAvailable];\n}];\n\n// Using a block with a C API follows the same alignment and spacing\n// rules as with Objective-C.\ndispatch_async(_fileIOQueue, ^{\n    NSString* path = [self sessionFilePath];\n    if (path) {\n        // ...\n    }\n});\n\n// An example where the parameter wraps and the block declaration fits\n// on the same line. Note the spacing of |^(SessionWindow *window) {|\n// compared to |^{| above.\n[[SessionService sharedService]\n    loadWindowWithCompletionBlock:^(SessionWindow *window) {\n        if (window) {\n            [self windowDidLoad:window];\n        } else {\n            [self errorLoadingWindow];\n        }\n    }];\n\n// Large blocks can be declared out-of-line.\nvoid (^largeBlock)(void) = ^{\n    // ...\n};\n[_operationQueue addOperationWithBlock:largeBlock];\n```\n\n### Braces\n\nWhen 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.\n```objective-c\n// Bad\n- (void)someMethod {\n    // Do something\n}\n\n// Good\n- (void)someMethod\n{\n    // Do something\n}\n\n// Good\nif (condition) {\n    // Do something\n}\n\n// Good\nfor (int i=0; i \u003c len; i++) {\n    // Do something\n}\n```\n\n### If Statements\n\nWhen 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.\n```objective-c\n// Good\nif (someValue != nil) {\n    [self doSomething];\n}\n\n// Good\nif (someReallyLongVariableName != nil\n    \u0026\u0026 someOtherLongVariableName != nil)\n{\n    [self doSomething];\n}\n\n// Bad\nif (someValue != nil)\n    [self doSomething];\n```\n\n### Ternary Operators\n\nBe 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.\n\n```objective-c\n\n// Good\n    int minVal = (a \u003c b) ? a : b\n\n// Bad\n    [self.view addSubview:((currentlyVisibleView == self.photoSelectorView) ? self.textEditorView : self.photoSelectorView)];\n\n```\n\n### Multi Line Declarations\n\nDon'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.\n\n```objective-c\n\n// Bad\n@property (nonatomic, copy) NSString *username, *url, *password;\n\n// Good\n@property (nonatomic, copy) NSString *username;\n@property (nonatomic, copy) NSString *url;\n@property (nonatomic, copy) NSString *password;\n\n```\n\n## Naming\nNaming 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.\n\nWhen writing pure Objective-C code, we mostly follow standard [Objective-C naming rules](http://developer.apple.com/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html).\n\nAny 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_.\n\n```objective-c\n- (void)displayWebsite:(NSURL *)websiteURL\n{\n    ...\n}\n\n- (void)displayWebsite:(NSString *)websiteUrl\n{\n    ...\n}\n```\n\n### File Names\nFile names should reflect the name of the class implementation that they contain—including case.  \n\nFile names for categories should include the name of the class being extended, e.g. _NSString+Helpers.h_ or _UIColors+Helpers.h_\n\n### Class Names\nClass names (along with category and protocol names) should start as uppercase and use mixed case to delimit words.\n\nIn 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_).\n\n### Objective-C Method Names\nMethod names should start as lowercase and then use mixed case. Each named parameter should also start as lowercase.  \nThe 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.  \n\nAccessor methods should be named the same as the variable they're \"getting\", but they should not be prefixed with the word \"get\". For example:\n```objective-c\n- (id)getDelegate;  // AVOID\n- (id)delegate;    // GOOD\n```\n\n### Variable Names\nVariables names start with a lowercase and use mixed case to delimit words. Instance variables have leading underscores. For example: _myLocalVariable_, *_myInstanceVariable*.  \n\n**Common Variable Names**\n\nDo 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:\n```objective-c\n// Bad\nint w;\nint nerr;\nint nCompConns;\ntix = [[NSMutableArray alloc] init];\nobj = [someObject object];\np = [network port];\n\n// Good\nint numErrors;\nint numCompletedConnections;\ntickets = [[NSMutableArray alloc] init];\nuserInfo = [someObject object];\nport = [network port];\n```\n**Instance Variables**  \nInstance variables are mixed case and should be prefixed with an underscore e.g. *_usernameTextField*.\n\n### Comments\nThough 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.  \n\nWhen 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!  \n\n**File Comments**  \nA file may optionally start with a description of its contents.\nEvery file should contain the following items, in order:\n* GPL License\n* a basic description of the contents of the file if necessary.\n\nIf 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.\n\n**Declaration Comments**  \nEvery interface, category, and protocol declaration should have an accompanying comment describing its purpose and how it fits into the larger picture.\n```objective-c\n// A delegate for NSApplication to handle notifications about app\n// launch and shutdown. Owned by the main app controller.\n@interface MyAppDelegate : NSObject {\n    ...\n}\n@end\n```\nIf 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.  \n\nAdditionally, each method in the public interface should have a comment explaining its function, arguments, return value, and any side effects.  \n\nDocument 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.\n\n## Cocoa and Objective-C Features\n### Interface files\n\nInterface 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.\n\n### Overridden NSObject Method Placement\nIt 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.\n\n### Initialization\nDon't initialize variables to _0_ or _nil_ in the init method; it's redundant.  \n\nAll 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_.\n\n### Keep the Public API Simple\nKeep your class simple; avoid \"kitchen-sink\" APIs. If a method doesn't need to be public, don't make it so.  \n\n### Use Root Frameworks\nInclude root frameworks over individual files.  \n\nWhile 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.\n```objective-c\n// good\n#import \u003cFoundation/Foundation.h\u003e\n\n// avoid\n#import \u003cFoundation/NSArray.h\u003e\n...\n```\n\n### Avoid Accessors During init and dealloc\nInstance subclasses may be in an inconsistent state during _init_ and _dealloc_ method execution, so code in those methods should avoid invoking accessors.  \n\nSubclasses 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.\n\n```objective-c\n// Good\n\n- (id)init\n{\n    self = [super init];\n    if (self) {\n        _bar = [[NSMutableString alloc] init];\n    }\n    return self;\n}\n\n- (void)dealloc\n{\n    [_bar release];\n    [super dealloc];\n}\n\n// Avoid\n\n- (id)init\n{\n    self = [super init];\n    if (self) {\n        self.bar = [NSMutableString string];\n    }\n    return self;\n}\n\n- (void)dealloc\n{\n    self.bar = nil;\n    [super dealloc];\n}\n```\n### Setters copy NSStrings\nSetters taking an _NSString_, should always copy the string it accepts.  \n\nNever 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_.  \n\n```objective-c\n- (void)setFoo:(NSString *)aFoo\n{\n    [_foo autorelease];\n    _foo = [aFoo copy];\n}\n```\n\n### nil Checks\nUse _nil_ checks for logic flow only.  \n\nUse _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).\n\n### BOOL Pitfalls\nBe careful when converting general integral values to _BOOL_. Avoid comparing directly with _YES_.  \n\n_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.  \n\nYou 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.  \n\nUsing logical operators (_\u0026\u0026_, _||_ and _!_) with _BOOL_ is also valid and will return values that can be safely converted to _BOOL_ without the need for a ternary operator.\n\n```objective-c\n// Bad\n\n- (BOOL)isBold\n{\n    return [self fontTraits] \u0026 NSFontBoldTrait;\n}\n- (BOOL)isValid\n{\n    return [self stringValue];\n}\n\n// Good\n- (BOOL)isBold\n{\n    return ([self fontTraits] \u0026 NSFontBoldTrait) ? YES : NO;\n}\n- (BOOL)isValid\n{\n    return [self stringValue] != nil;\n}\n- (BOOL)isEnabled\n{\n    return [self isValid] \u0026\u0026 [self isBold];\n}\n```\nAlso, 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.\n```objective-c\n// Bad\nBOOL great = [foo isGreat];\nif (great == YES)\n    // ...be great!\n\n//Good\nBOOL great = [foo isGreat];\nif (great)\n    // ...be great!\n```\n### Properties\nUse of the _@property_ directive is preferred. Dot notation is allowed only for access to a declared @property.\n\nUse of automatically synthesized instance variables is preferred.\n\n**Location**  \n\nA 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.\n```objective-c\n@interface MyClass : NSObject\n@property(copy, nonatomic) NSString *name;\n@end\n\n@implementation MyClass\n\n- (id)init\n{\n    ...\n}\n@end\n```\n**Use Copy Attribute For Strings**  \nNSString properties should always be declared with the _copy_ attribute.  \n\nThis logically follows from the requirement that setters for NSStrings always must use _copy_ instead of _retain_.  \n\n**Dot notation**  \nDot 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.\n```objective-c\n// Good\nNSString *oldName = myObject.name;\nmyObject.name = @\"Alice\";\nNSArray *array = [[NSArray arrayWithObject:@\"hello\"] retain];\n\n// Bad\nNSUInteger numberOfItems = array.count;  // not a property\narray.release;                           // not a property\n```\n### Interfaces Without Instance Variables\nOmit the empty set of braces on interfaces that do not declare any instance variables.\n```objective-c\n// Good\n@interface MyClass : NSObject\n// Does a lot of stuff\n- (void)fooBarBam;\n@end\n\n// Bad\n@interface MyClass : NSObject {\n}\n// Does a lot of stuff\n- (void)fooBarBam;\n@end\n```\n\n### NSNumber, NSArray and NSDictionary  Literals\nFor 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.\n\nNSNumber literals are used just like Objective C string literals. Boxing is used when necessary.\n```objective-c\n// NSNumber\nNSNumber *fortyTwo = @42;\nNSNumber *piOverTwo = @(M_PI / 2);\ntypedef NS_ENUM(NSUInteger, MyEnum) {\n    MyEnumOne,\n    MyEnumTwo = 2,\n};\nNSNumber *myEnum = @(MyEnumTwo);\n\n// NSArray\nNSArray *continents = @[@\"North America\", @\"South America\", @\"Europe\", @\"Asia\", @\"Africa\", @\"Antarctica\", @\"Australia\"];\n\n// NSDictionary\nNSDictionary *personInfo = @{ @\"name\" : @\"John Doe\", @\"age\" : @(25) };\n```\n\n### Constant definitions\n\nAvoid using `#define` for constants, they should be defined using `const`. Constant names should start with an uppercase letter and use mixed case.\n\n```objective-c\n// Good\nNSInteger const ReaderPostsToSync = 20;\nNSString *const ReaderLastSyncDateKey = @\"ReaderLastSyncDate\";\n\n// Bad\n#define READER_POSTS_TO_SYNC 20;\n#define READER_SYNC_DATE_KEY @\"ReaderLastSyncDate\";\n```\n\nConstants 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:\n\n```objective-c\n//  Blog+Jetpack.h\nextern NSString * const BlogJetpackErrorDomain;\n\n//  Blog+Jetpack.m\nNSString * const BlogJetpackErrorDomain = @\"BlogJetpackError\";\n```","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwordpress-mobile%2Fobjective-c-style-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwordpress-mobile%2Fobjective-c-style-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwordpress-mobile%2Fobjective-c-style-guide/lists"}