无规矩不成方圆

iOS Guidelines

Project Structure

  • Organized .xcodeproj: files are grouped by layers (Presentation, Domain/Model, Infrastructure, etc), responsibilities (UI, Model, Logic, Vendor, etc), roles, etc. No flat structure allowed

  • Organized project folder: desirable but not required to keep file structure in sync with .xcodeproj

  • One .m / .swift == One class. No extra classes allowed

  • Localization is required even for the case, when you have only one language. Therefore adding extra language won't cause any difficulty in future

  • Images and other resources (.plist) should be grouped as well (i.e. $SRCROOT/Resources/Images/Common/, $SRCROOT/Resource/Assets/)

File Structure (.m)

  • Structure
imports

related constants

class extension

@implementation
- dealloc
- init methods
- other
@end

  • Method sections should be separated by #pragma mark - $sectionName

Braces, Asterisk

  • 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

  • Asterisk placed near the name Type *var = ...;

  • Every code block should be wrapped by {}:


if (statement) {
    NSLog(@"%@", var);
}

The only exception is a short statement and an immediate return in the beginning:


- (void)performSomeTask {
    if (!user.hasToken) return;
    ...
}

Spaces, Formatting

General

  • Tab consists of 4 spaces

  • Max symbols in a row: 120

  • Use space after if, while, for and similar:


if (pointer != someOtherPointer)

CGFloat result = width * height * 2.f;

BOOL contentExists = self.content.length > 0;

for (int i = 0; i < x; i++) { ... }

  • Alignment: do not align code as ASCII-art.

  • Separate logical code blocks with 1 line wrap. Random number of \n is not allowed

Variable declaration

  • Between Type & Protocol there are no spaces:
id object = ...;
  • Between var and casting parentheses there are no spaces:

ClassType *a = (ClassType *)b;,
ScalarType a = (ScalarType)b;

Class Declaration

  • If listing protocols goes beyond 120 characters, place each on a separate line:

@interface SCHCategoryViewController : UIViewController  

@interface SCHCategoryViewController : UIViewController <
    UITableViewDelegate, 
    UITableViewDataSource, 
    SCHSyncronizationDelegate
>

Method Declaration

  • Use a single space between +/- and a returned type. Any additional spaces in arguments list are not allowed:

- (void)doSomethingWithString:(NSString *)string flag:(BOOL)flag;

  • If the method goes beyond 120+10 characters, place each argument on a separate line, align by colon:

- (void)doSomethingWithString:(NSString *)string
                         rect:(CGRect)rectangle
                       length:(NSUInteger)length;

Method Invocation

  • Method invocation should use the same formatting as for declaration

Function Declaration

  • No space symbol between name and arguments parentheses

  • 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:


void * LongLongLongFunction(
    id firstArgument, 
    id secondArgument,
    id *outArgument,
    int other
)

NSAssert(
    [controller conformsToProtocol:@protocol(EParticipantSelection)],
    @"Controller %@ should confrom to protocol",
    NSStringFromProtocol(@protocol(EParticipantSelection))
);

Access specifiers & ivars

  • @public, @private, @protected should be aligned by 1 tab:

@interface MyClass : NSObject {
    @private
    id _privateIvar;

    @protected
    id _protectedIvar;
}

  • Access specifiers should be declared explicitly

Property Declaration

  • Between @property and opening parentheses 1 space symbol should be used

  • Parameters ordering: atomic/nonatomic, memory policy, access specified (readonly/readwrite), setter declaration, getter declaration:
    @property (nonatomic, copy, readonly, getter=customGetter) NSString *value;

Protocol Declaration

  • @required and @optional aligned to the line beginning

Blocks / Closures Declaration

  • Code inside block / closure aligned by 1 tab

  • Opening and closing braces should be aligned by the first symbol of declaration:


dipatch_async(dispatch_get_main_queue(), ^{
    // your code here

});

NSArray *contentArray = nil;
[contentArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
     // your code here
}];

[UIView animateWithDuration:0.3 animations:^{
    // your code here
} completion:^(BOOL finished){
     // your code here
}];

  • There is no space between ^ and return type / arguments: ^(id response){} ^NSUInteger * (id response){}

Naming

In general we're using Apple Coding Guidelines for Cocoa with several highlights:

  • Three-letters prefix is REQUIRED

  • Methods for the non-project class categories should be prefixed by

lowercasePrefix_:
- (void)sch_performTask:(id)arg

Constants

  • Magical numbers are not allowed - constants should be used instead. Exception: constant value, used in local one place with descriptive name

  • No "raw" strings. Exception: the same as for the magical numbers

  • Desirable to use extern keyword:

// SCHNotifier.h
OBJC_EXTERN NSString * const SCHNotifierDidChangeStateNotification;
OBJC_EXTERN const CGFloat SCHDefaultAnimationDuration;

// SCHNotifier.m

NSString * const SCHNotifierDidChangeStateNotification = @"com.project.notifier.stateDidChange";
const CGFloat SCHDefaultAnimationDuration = 0.33;

Required / recommended best practices

Types Declaration / Usage

  • Use typedef for blocks declaration and custom enums / scalar types

  • Use NSInteger, NSTimeInterval, CGFloat, etc over plain types. Therefore it is
    easier to migrate to the 64-bits

Forward Declaration

Use forward declaration whenever possible

Ivars

@public ivars not allowed

Properties

  • Use copy specifier in case mutability leads to unexpected behaviour (i.e. when NSMutableString passed as NSString and mutated outside of the class)

  • Use readonly for public properties whenever possible to prevent unexpected class usage (i.e. outlet assigned from client code, etc)

  • (iOS only) Use nonatomic whenever possible to speedup code execution

  • Desirable to access underlying property's ivar only in init/setter/getter

  • Use of @property solely to create _ivar is not recommended and should be prohibited

Exceptions handling

Use exceptions only where it is required. Desirable to use NSError ** and / or return result status (i.e. Success, Fail)

Protocols

  • Delegate methods should always pass sender argument:
@protocol CustomClassDelegate 

- (NSInteger)someDelegateMethod:(CustomClass *)customClass;
- (void)customClass:(CustomClass *)customClass didSelectRowAtIndexPath:(NSIndexPath *)indexPath;

@end
  • Protocol support for properties / vars should be declared explicitly:

id instance = ...;, @property (nonatomic, weak) id delegate;

Boolean statements

  • Desirable to use implicit equality check: if (bar && baz && quux)

Preprocessor usage

  • Prefer c-functions / constants / methods over #define

AppDelegate

Keep your AppDelegate as clean as possible. Any logic, not related to AppDelegate (database seeding, networking, etc) is not allowed

Clean .pch

Group required #defines, constants to a separate header (SCHConstants.h, SCHDefines.h). Garbage in .pch is not allowed

你可能感兴趣的:(无规矩不成方圆)