-
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 *textunless it'sNSString * const Text
-
Lean towards clarity over compactness
-
Avoid single letter variables. Try using
idx/jdxinstead ofi/jin for loops. -
Acronyms should be all lowercase as a method prefix (ex:
urlorurlString). Otherwise, they should be all caps when occurring elsewhere in the method name, or as a class name (ex:handleStripeURLCallbackWithURLorSTPAPIClient) -
Internal or private methods and ivars should begin with an
_, e.g.- (void)_doPrivateStuffandid _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 ifandelseon 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";switchstatements 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/Basic Integration/Basic Integration/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
@classfor 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_ENDin headers.NS_ASSUME_NON_NULL_BEGIN/NS_ASSUME_NON_NULL_ENDshould 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.hfile. 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
copyfor classes with mutable counterparts such asNSString,NSArray,NSDictionary -
Leverage auto property synthesis whenever possible
-
Declare
@synthesizeand@dynamicon 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…),deallocmethods, 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
#defineto define a block of code --#definecode 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