└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # iOS Guidelines 2 | 3 | ## Project Structure 4 | - Organized .xcodeproj: files are grouped by layers (Presentation, Domain/Model, Infrastructure, etc), responsibilities (UI, Model, Logic, Vendor, etc), roles, etc. No flat structure allowed 5 | - Organized project folder: desirable but not required to keep file structure in sync with .xcodeproj 6 | - *One .m / .swift == One class*. No extra classes allowed 7 | - Localization is required even for the case, when you have only one language. Therefore adding extra language won't cause any difficulty in future 8 | - Images and other resources (.plist) should be grouped as well (i.e. $SRCROOT/Resources/Images/Common/, $SRCROOT/Resource/Assets/) 9 | 10 | ## File Structure (.m) 11 | - Structure 12 | ``` 13 | imports 14 | 15 | related constants 16 | 17 | class extension 18 | 19 | @implementation 20 | - dealloc 21 | - init methods 22 | - other 23 | @end 24 | ``` 25 | - Method sections should be separated by #pragma mark - $sectionName 26 | 27 | ## Braces, Asterisk 28 | - Curly braces are opened on the same line with code, closed - on a new line. For short blocks / closures a single line can be used 29 | - Asterisk placed near the name ```Type *var = ...;``` 30 | - Every code block should be wrapped by ```{}```: 31 | ```objective-c 32 | if (statement) { 33 | NSLog(@"%@", var); 34 | } 35 | ``` 36 | The only exception is a short statement and an immediate return in the beginning: 37 | ```objective-c 38 | - (void)performSomeTask { 39 | if (!user.hasToken) return; 40 | ... 41 | } 42 | ``` 43 | 44 | ## Spaces, Formatting 45 | #### General 46 | - Tab consists of 4 spaces 47 | - Max symbols in a row: *120* 48 | - Use space after ```if```, ```while```, ```for``` and similar: 49 | ```objective-c 50 | if (pointer != someOtherPointer) 51 | 52 | CGFloat result = width * height * 2.f; 53 | 54 | BOOL contentExists = self.content.length > 0; 55 | 56 | for (int i = 0; i < x; i++) { ... } 57 | ``` 58 | - Alignment: do not align code as ASCII-art. 59 | - Separate logical code blocks with 1 line wrap. Random number of \n is not allowed 60 | 61 | #### Variable declaration 62 | - Between Type & Protocol there are no spaces: ```id object = ...;``` 63 | - Between var and casting parentheses there are no spaces: ```ClassType *a = (ClassType *)b;```, ```ScalarType a = (ScalarType)b;``` 64 | 65 | #### Class Declaration 66 | - If listing protocols goes beyond 120 characters, place each on a separate line: 67 | ```objective-c 68 | @interface SCHCategoryViewController : UIViewController 69 | 70 | @interface SCHCategoryViewController : UIViewController < 71 | UITableViewDelegate, 72 | UITableViewDataSource, 73 | SCHSyncronizationDelegate 74 | > 75 | ``` 76 | 77 | #### Method Declaration 78 | - Use a single space between +/- and a returned type. Any additional spaces in arguments list are not allowed: 79 | ```- (void)doSomethingWithString:(NSString *)string flag:(BOOL)flag;``` 80 | - If the method goes beyond 120+10 characters, place each argument on a separate line, align by colon: 81 | ```objective-c 82 | - (void)doSomethingWithString:(NSString *)string 83 | rect:(CGRect)rectangle 84 | length:(NSUInteger)length; 85 | ``` 86 | #### Method Invocation 87 | - Method invocation should use the same formatting as for declaration 88 | 89 | #### Function Declaration 90 | - No space symbol between name and arguments parentheses 91 | - If the method goes beyond 120+10 characters, parentheses should be placed the same way, as opening/closing braces. Place each argument on a separate line aligned by 1 tab: 92 | ```objective-c 93 | void * LongLongLongFunction( 94 | id firstArgument, 95 | id secondArgument, 96 | id *outArgument, 97 | int other 98 | ) 99 | 100 | NSAssert( 101 | [controller conformsToProtocol:@protocol(EParticipantSelection)], 102 | @"Controller %@ should confrom to protocol", 103 | NSStringFromProtocol(@protocol(EParticipantSelection)) 104 | ); 105 | ``` 106 | 107 | #### Access specifiers & ivars 108 | - ```@public```, ```@private```, ```@protected``` should be aligned by 1 tab: 109 | ```objective-c 110 | @interface MyClass : NSObject { 111 | @private 112 | id _privateIvar; 113 | 114 | @protected 115 | id _protectedIvar; 116 | } 117 | ``` 118 | - Access specifiers should be declared explicitly 119 | 120 | #### Property Declaration 121 | - Between ```@property``` and opening parentheses 1 space symbol should be used 122 | - Parameters ordering: atomic/nonatomic, memory policy, access specified (readonly/readwrite), setter declaration, getter declaration: ```@property (nonatomic, copy, readonly, getter=customGetter) NSString *value;``` 123 | 124 | #### Protocol Declaration 125 | - ```@required``` and ```@optional``` aligned to the line beginning 126 | 127 | #### Blocks / Closures Declaration 128 | - Code inside block / closure aligned by 1 tab 129 | - Opening and closing braces should be aligned by the first symbol of declaration: 130 | ```objective-c 131 | dipatch_async(dispatch_get_main_queue(), ^{ 132 | // your code here 133 | }); 134 | 135 | NSArray *contentArray = nil; 136 | [contentArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){ 137 | // your code here 138 | }]; 139 | 140 | [UIView animateWithDuration:0.3 animations:^{ 141 | // your code here 142 | } completion:^(BOOL finished){ 143 | // your code here 144 | }]; 145 | ``` 146 | - There is no space between ```^``` and return type / arguments: ```^(id response){}``` ```^NSUInteger * (id response){}``` 147 | 148 | ## Naming 149 | In general we're using [Apple Coding Guidelines for Cocoa](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingBasics.html#//apple_ref/doc/uid/20001281-BBCHBFAH) with several highlights: 150 | - Three-letters prefix is REQUIRED 151 | - Methods for the non-project class categories should be prefixed by ```lowercasePrefix_```: 152 | ```- (void)sch_performTask:(id)arg``` 153 | 154 | ## Constants 155 | - Magical numbers are not allowed - constants should be used instead. Exception: constant value, used in local one place with descriptive name 156 | - No "raw" strings. Exception: the same as for the magical numbers 157 | - Desirable to use ```extern``` keyword: 158 | ```objective-c 159 | // SCHNotifier.h 160 | OBJC_EXTERN NSString * const SCHNotifierDidChangeStateNotification; 161 | OBJC_EXTERN const CGFloat SCHDefaultAnimationDuration; 162 | 163 | // SCHNotifier.m 164 | 165 | NSString * const SCHNotifierDidChangeStateNotification = @"com.project.notifier.stateDidChange"; 166 | const CGFloat SCHDefaultAnimationDuration = 0.33; 167 | ``` 168 | 169 | ## Required / recommended best practices 170 | #### Types Declaration / Usage 171 | - Use typedef for blocks declaration and custom enums / scalar types 172 | - Use NSInteger, NSTimeInterval, CGFloat, etc over plain types. Therefore it is easier to migrate to the 64-bits 173 | 174 | #### Forward Declaration 175 | Use [forward declaration](http://railsware.com/blog/2013/08/09/using-forward-declaration-in-your-objective-c-projects/) whenever possible 176 | 177 | #### Ivars 178 | ```@public``` ivars not allowed 179 | 180 | #### Properties 181 | - Use ```copy``` specifier in case mutability leads to unexpected behaviour (i.e. when NSMutableString passed as NSString and mutated outside of the class) 182 | - Use ```readonly``` for public properties whenever possible to prevent unexpected class usage (i.e. outlet assigned from client code, etc) 183 | - (iOS only) Use ```nonatomic``` whenever possible to speedup code execution 184 | - Desirable to access underlying property's ivar only in init/setter/getter 185 | - Use of @property solely to create _ivar is not recommended and should be prohibited 186 | 187 | #### Exceptions handling 188 | Use exceptions only where it is required. Desirable to use NSError ** and / or return result status (i.e. Success, Fail) 189 | 190 | #### Protocols 191 | - Delegate methods should always pass ```sender``` argument: 192 | ```objective-c 193 | @protocol CustomClassDelegate 194 | 195 | - (NSInteger)someDelegateMethod:(CustomClass *)customClass; 196 | - (void)customClass:(CustomClass *)customClass didSelectRowAtIndexPath:(NSIndexPath *)indexPath; 197 | 198 | @end 199 | ``` 200 | - Protocol support for properties / vars should be declared explicitly: ```id instance = ...;```, ```@property (nonatomic, weak) id delegate;``` 201 | 202 | #### Boolean statements 203 | - Desirable to use implicit equality check: ```if (bar && baz && quux)``` 204 | 205 | #### Preprocessor usage 206 | - Prefer c-functions / constants / methods over #define 207 | 208 | #### AppDelegate 209 | Keep your AppDelegate as clean as possible. Any logic, not related to AppDelegate (database seeding, networking, etc) is not allowed 210 | 211 | #### Clean .pch 212 | Group required #defines, constants to a separate header (SCHConstants.h, SCHDefines.h). Garbage in .pch is not allowed 213 | --------------------------------------------------------------------------------