-
Indent using 4 spaces. No tabs.
-
Avoid starting methods with an empty line
-
There should not be a need to use multiple consecutive empty lines
-
Asterisks should be attached to the variable name
NSString *text
unless it'sNSString * const Text
-
Lean towards clarity over compactness
-
Avoid single letter variables. Try using
idx
/jdx
instead ofi
/j
in for loops. -
Acronyms should be all lowercase as a method prefix (ex:
url
orurlString
). Otherwise, they should be all caps when occurring elsewhere in the method name, or as a class name (ex:handleStripeURLCallbackWithURL
orSTPAPIClient
) -
Internal or private methods and ivars should begin with an
_
, e.g.- (void)_doPrivateStuff
andid _internalVariable
. This is not required for private properties which should not include an underscore (this is to distinguish them from their underlying variable which automatically has an_
prefix).
- Place
else if
andelse
on the same line as the preceding closing curly brace:
if (condition) {
// A
} else if (condition) {
// B
} else {
// C
}
-
Always wrap conditional bodies with curly braces
-
Each return statement should be on a separate line for ease of debugging. i.e. do NOT write
if (condition) return YES;
-
Use ternary operators sparingly and for simple conditions only:
type = isCard ? @"card" : @"unknown";
type = dictionary[@"type"] ?: @"default";
switch
statements for enums should contain an entry for each value and avoid usingdefault
- Document using the multi-line syntax in all cases with the content aligned with the first asterisk:
/**
This is a one line description for a simple method
*/
- (void)title;
/**
This is a multi-line description for a complicated method
@param
@see https://...
*/
- (void)title;
- Header documentation should wrap lines to 80 characters
- Use literals to create immutable instances of
NSString
,NSDictionary
,NSArray
,NSNumber
:
NSArray *brands = @[@"visa", @"mastercard", @"discover"];
NSDictionary *parameters = @{
@"currency": @"usd",
@"amount": @1000,
};
-
Dictionary colons should be attached to the key
-
Align multi-line literals using default Xcode indentation
- Use static constants whenever appropriate. Names should start with a capital letter:
static NSString * const HTTPMethodGET = @"GET";
static const CGFloat ButtonHeight = 100.0;
- Any public static constants should be prefixed with
STP
:
static NSString * const STPSDKVersion = @"11.0.0";
-
We use flat folder structure on disk with some exceptions
-
Save files to the appropriate root level folder. Typical folders include:
stripe-ios/Stripe/
stripe-ios/Tests/Tests/
stripe-ios/Example/Non-Card Payment Examples/Non-Card Payment Examples/
-
Save public header files in
stripe-ios/Stripe/PublicHeaders/
for Cocoapods and Swift Package Manager compatibility
- Ordering for imports in headers
- Import system frameworks
- Import superclasses and protocols sorted alphabetically
- Use
@class
for everything else
#import <Foundation/Foundation.h>
#import "STPAPIResponseDecodable.h"
#import "STPBankAccountParams.h"
@class STPAddress, @STPToken;
- Ordering for imports in implementations
- Import system frameworks
- Import corresponding headers
- Import everything else sorted alphabetically
#import <PassKit/PassKit.h>
#import "STPSource.h"
#import "STPSource+Private.h"
#import "NSDictionary+Stripe.h"
#import "STPSourceOwner.h"
#import "STPSourceReceiver.h"
#import "STPSourceRedirect.h"
#import "STPSourceVerification.h"
-
Stick to Xcode default spacing for interfaces, categories, and protocols
-
Always define
NS_ASSUME_NON_NULL_BEGIN
/NS_ASSUME_NON_NULL_END
in headers.NS_ASSUME_NON_NULL_BEGIN
/NS_ASSUME_NON_NULL_END
should also be used in implementation (.m
) files
NS_ASSUME_NON_NULL_BEGIN
@protocol STPSourceProtocol <NSObject>
// ...
@end
// ...
@interface STPSource : NSObject<STPAPIResponseDecodable, STPSourceProtocol>
// ...
@end
// ...
@interface STPSource () <STPInternalAPIResponseDecodable>
// ...
@end
NS_ASSUME_NON_NULL_END
- Category methods on certain classes need to be prefixed with
stp_
to avoid collision:
// NSDictionary+Stripe.h
@interface NSDictionary (Stripe)
- (NSDictionary *)stp_jsonDictionary;
@end
-
Define private properties and methods as class extensions inside the implementation. Ex:
STPSource.m
. -
Define internal properties and methods as class extensions inside a
+Private.h
file. Ex:STPSource+Private.h
. -
Access private properties and methods from test classes by defining a class extension inside the test implementation:
// STPBankAccountTest.m
@interface STPBankAccount ()
+ (STPBankAccountStatus)statusFromString:(NSString *)string;
+ (NSString *)stringFromStatus:(STPBankAccountStatus)status;
@end
@interface STPBankAccountTest : XCTestCase
@end
@implementation STPBankAccountTest
// ...
@end
- Properties should be defined using this syntax:
@property (<nonatomic / atomic>, <weak / copy / _>, <nullable / _>, <readonly / _>) <class> *<name>;
@property (<nonatomic / atomic>, <readonly / _>) <type> <name>;
-
Omit default properties (
assign
,readwrite
,strong
) -
Use
copy
for classes with mutable counterparts such asNSString
,NSArray
,NSDictionary
-
Leverage auto property synthesis whenever possible
-
Declare
@synthesize
and@dynamic
on separate lines for shorter diffs -
Use properties (
self.foo
) instead of their corresponding instance variables (_foo
). Instance variables should only be accessed directly in initializer methods (init
,initWithCoder:
, etc…),dealloc
methods, and within custom getters and setters. For more information, see Apple’s docs on using accessor methods in initializer methods and dealloc..
- (instancetype)init {
self = [super init];
if (self) {
// ...
}
return self;
}
-
If a method takes more than three arguments, each argument should be on a separate line.
-
Do not use
#define
to define a block of code --#define
code is very difficult to debug -
Use
#pragma mark - <text>
and#pragma mark <text>
to group methods In large implementation files:
#pragma mark - Button Handlers
#pragma mark - UITableViewDataSource
#pragma mark - UITableViewDelegate