├── CONTRIBUTING.md ├── LICENSE.md └── README.md /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | Contributions are welcomed. Open a pull-request or an issue. 3 | 4 | ## Code of conduct 5 | This project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are expected to honor this code. 6 | 7 | [code-of-conduct]: https://github.com/spotify/code-of-conduct/blob/master/code-of-conduct.md 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | This work is licensed under the Creative Commons Attribution 4.0 International License. 2 | 3 | To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/. 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Spotify Objective-C Coding Style 2 | ================================ 3 | 4 | Version: 0.9.0 5 | 6 | Our general coding conventions at Spotify are documented on an internal wiki, but specifics for Objective-C and 7 | Objective-C++ code in the iOS client are documented here. 8 | 9 | License 10 | ------- 11 | Copyright (c) 2015-2016 Spotify AB. 12 | 13 | This work is licensed under a [Creative Commons Attribution 4.0 International License]( http://creativecommons.org/licenses/by/4.0/). 14 | 15 | Table of Contents 16 | ----------------- 17 | 18 | 1. [Spacing, Lines and Formatting](#spacing-lines-and-formatting) 19 | 2. [Brackets](#brackets) 20 | 3. [Naming](#naming) 21 | 4. [Comments](#comments) 22 | 5. [Pragma Marks](#pragma-marks) 23 | 6. [Constants](#constants) 24 | 7. [Return Early](#return-early) 25 | 8. [Initializers](#initializers) 26 | 9. [Headers](#headers) 27 | 10. [Nullability](#nullability) 28 | 11. [Strings](#strings) 29 | 12. [Dot Notation](#dot-notation) 30 | 13. [Categories](#categories) 31 | 32 | Spacing, Lines and Formatting 33 | ----------------------------- 34 | 35 | ### Line length 36 | * Keep your lines within **120** characters width when possible. 37 | * In Xcode, you can set a page guide in Text Editing in Preferences. 38 | 39 | ### Whitespace 40 | * Use **4** spaces for indentation and alignment. Do not use tabs. 41 | * Trailing whitespace is acceptable only on blank lines, but discouraged even there. 42 | * In Xcode, select "Automatically trim whitespace" and "Including whitespace-only lines" in Text Editing preferences 43 | to handle this automatically. 44 | * Put spaces after commas, and before and after operators. 45 | * Do not put spaces between parentheses and what they are enclosing. 46 | 47 | **Example:** 48 | ```objc 49 | foo("bar") 50 | ``` 51 | 52 | **Not:** 53 | 54 | ```objc 55 | foo( "bar" ) 56 | ``` 57 | 58 | ### Containers 59 | * Array one-liners are acceptable unless they have too many items or their values are too long. 60 | 61 | ```objc 62 | NSArray *array = @[@"uno", @"dos", @"tres", @"cuatro"]; 63 | ``` 64 | 65 | * In that case, break them in several lines: 66 | 67 | ```objc 68 | NSArray *array = @[ 69 | @"This is how we do, yeah, chilling, laid back", 70 | @"Straight stuntin’ yeah we do it like that", 71 | @"This is how we do, do do do do, this is how we do", 72 | ]; 73 | ``` 74 | 75 | * Dictionary one-liners are reserved for single pairs only: 76 | 77 | ```objc 78 | NSDictionary *dict = @{@"key" : @"highway"}; 79 | ``` 80 | 81 | * Format it pretty otherwise, leaving a trailing comma after the last item: 82 | ```objc 83 | NSDictionary *dict = @{ 84 | @"key1" : @"highway", 85 | @"key2" : @"heart", 86 | }; 87 | ``` 88 | 89 | Brackets 90 | -------- 91 | * Always use brackets for `if` / `for` / `while` / `do`-`while` statements. Even if its a one-liner: 92 | 93 | ```objc 94 | if (itsMagic) { 95 | [self makeItEverlasting]; 96 | } 97 | ``` 98 | 99 | * Write follow up `else` clauses after the previous closing bracket on the same line. 100 | 101 | ```objc 102 | if (hasClue) { 103 | knowExactlyWhatToDo(); 104 | } else if (seeItAllSoClear) { 105 | writeItDown(); 106 | } else { 107 | sing(); 108 | dance(); 109 | } 110 | ``` 111 | 112 | Naming 113 | ------ 114 | * Follow Apple’s [Coding Guidelines for Cocoa](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html) 115 | on naming. 116 | 117 | Comments 118 | -------- 119 | * Use the `//` style for single line comments or when appending comments in the same line of code. 120 | * Use the `/* */` style for multi-line comments. 121 | 122 | **Example:** 123 | ```objc 124 | /* 125 | This is a multi-line comment. The opening and closing markers are on their 126 | own lines. 127 | 128 | This is a new paragraph in the same block comment. 129 | */ 130 | 131 | stop(); // Hammer-time! 132 | 133 | // this is a very brief comment. 134 | ``` 135 | 136 | * Document all methods and properties in the headers using Xcode’s documentation style (which is `///` at the time of writing). 137 | You can select a property or method and use `Option`+`Cmd`+`/` to generate the documentation template for it. Make sure to use the available 138 | markup tags like `@param`, `@return`, etc. (these will be auto-generated for you by Xcode). 139 | 140 | Pragma Marks 141 | ------------ 142 | * Use the pre-processor instruction `#pragma mark` to mark related groups of methods. 143 | 144 | Constants 145 | --------- 146 | * Do not define constants using `#define`. 147 | * Publicly (or privately) exposed variables should be constant (trying to assign values will result in compilation 148 | error). 149 | 150 | ```objc 151 | extern NSString * const SPTCodeStandardErrorDomain; 152 | ``` 153 | 154 | Return Early 155 | ------------ 156 | * Return early on errors and failed pre-conditions to avoid unnecessary nested brackets and / or unnecessary 157 | computations. 158 | 159 | **Example:** 160 | 161 | ```objc 162 | - (void)setFireToTheRain:(id)rain 163 | { 164 | if ([_rain isEqualTo:rain]) { 165 | return; 166 | } 167 | 168 | _rain = rain; 169 | } 170 | ``` 171 | 172 | Initializers 173 | ------------ 174 | * Follow [Apple's typical init format](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html#//apple_ref/doc/uid/TP40011210-CH5-SW11) to initialize objects. 175 | 176 | **Example:** 177 | 178 | ```objc 179 | - (instancetype)init 180 | { 181 | self = [super init]; 182 | 183 | if (self) { 184 | // initialize instance variables here 185 | } 186 | 187 | return self; 188 | } 189 | ``` 190 | 191 | Headers 192 | ------- 193 | * The use of prefix headers has been deprecated. Do not add new code to an existing prefix header. 194 | * When importing a module use the hash-import variant instead of at-import. 195 | * Yes: `#import ` 196 | * No: `@import Foundation;` 197 | 198 | Nullability 199 | ----------- 200 | * Use `NS_ASSUME_NONNULL_BEGIN` and `NS_ASSUME_NONNULL_END` in header files, and explicitly add `nullable` when needed. Example: 201 | ```objc 202 | #import 203 | 204 | @protocol SPTPlaylist; 205 | 206 | NS_ASSUME_NONNULL_BEGIN 207 | 208 | typedef void(^SPTSomeBlock)(NSData * _Nullable data, NSError * _Nullable error); 209 | 210 | @interface SPTYourClass : NSObject 211 | 212 | @property (nonatomic, copy, readonly, nullable) NSString *customTitle; 213 | @property (nonatomic, strong, readonly) id playlist; 214 | 215 | - (nullable instancetype)initWithPlaylist:(id)playlist 216 | customTitle:(nullable NSString *)customTitle; 217 | 218 | @end 219 | 220 | NS_ASSUME_NONNULL_END 221 | ``` 222 | 223 | Strings 224 | ------- 225 | * All strings presented to the user should be localized. 226 | 227 | Dot Notation 228 | ------------ 229 | * Use bracket notation when calling non-accessor methods: 230 | 231 | ```objc 232 | [self doSomething]; 233 | ``` 234 | 235 | * Use bracket notation when accessing globals through a class method: 236 | 237 | ```objc 238 | [MyClass sharedInstance]; 239 | ``` 240 | 241 | * Set and access properties using dot notation: 242 | 243 | ```objc 244 | self.myString = @"A string"; 245 | ``` 246 | 247 | * Except in the `init` or `dealloc` methods, always use the ivar directly there: 248 | 249 | ```objc 250 | _myString = nil; 251 | ``` 252 | 253 | Categories 254 | ---------- 255 | * Methods in categories on non-Spotify classes must be prefixed `spt_` to avoid name clashes. 256 | --------------------------------------------------------------------------------