This document describes the Objective-C coding style of the iOS Mobile SDK team. This guideline is recommended to comply with all Objective-C implementations of our products.
Beyond the guidelines defined in this document, we also recommend reviewing the Apple official coding guidelines.
- Programming with Objective-C
- Cocoa Fundamentals Guide
- Coding Guidelines for Cocoa
- App Programming Guide for iOS
The iOS Mobile SDK Mobile consists of these frameworks:
- MASFoundation
- MASUI
- MASConnecta
- MASIdentityManagement
- MASStorage
All of frameworks are recommended to comply with the coding guideline. For more information about the iOS Mobile SDK, see developer website.
- Documentation
- Pragma Mark
- Class Naming
- Imports
- Constants
- Spacing / Newline
- Nullability for Swift
- Project Configuration Guideline
All code should be properly documented in .h
and .m
files. Code documentation should adhere to Apple Doc's format.
Our team uses a tool that automatically generates document format in Xcode called VVDocumenter available through Alcatraz.
Recommendation: Install Alcatraz and VVDocumenter. This tool automatically generates the proper documentation format for methods, properties, classes, and any other form of section required for documentation.
Recommended elements to document:
- Class description
- Property
- Enum type
- Constant
- Method
For private methods that are not available in a header file, the method should still be documented in the implementation file if it is only in .m
file.
# pragma mark -
categorizes methods or properties in the header and implementation files in Xcode. It makes the code easier to organize and navigate by other developers.
There are few a commonly used # pragma mark
in MASFoundation. Follow these guidelines for categories.
# pragma mark - Properties
# pragma mark - Lifecycle
# pragma mark - Public
# pragma mark - Private
These are commonly used # pragma mark -
in MASFoundation. Any other functional group of methods are fine, as long as it makes sense to everyone.
For example:
In MASDevice.h
, methods that are related to BLE functionalities could be grouped in # pragma mark - Bluetooth Central/Peripheral
.
Follow the standard format of pragma mark
that is also compatible with Apple Doc.
For example:
///--------------------------------------
/// @name Properties
///--------------------------------------
# pragma mark - Properties
Not:
#pragma mark -
#pragma mark - Properties
- Note: Allow one space between # and the pragma mark.
- Order of the
# pragma mark
matters. Place all of the commonly used# pragma mark
at the top, followed by the others. - Order of the
# pragma mark
should be identical in both header and implementation files. - All of the methods under
# pragma mark
should be in alphabetical order.
- Imports may or may not be in alphabetical order
- Always make use of foward declaration in the interface (.h) file. I.e.
@class MASObject
instead of#import "MASObject.h"
For example:
//
// All imported classes should be in alphabetical order
//
#import <MASFoundation/MASApplication.h>
#import <MASFoundation/MASAuthenticationProvider.h>
#import <MASFoundation/MASAuthenticationProviders.h>
#import <MASFoundation/MASConfiguration.h>
#import <MASFoundation/MASDevice.h>
#import <MASFoundation/MASFile.h>
#import <MASFoundation/MASGroup.h>
#import <MASFoundation/MASObject.h>
#import <MASFoundation/MASUser.h>
#import <MASFoundation/MASSessionSharingQRCode.h>
#import <MASFoundation/MASMessage.h>
Not:
#import <MASFoundation/MASObject.h>
#import <MASFoundation/MASAuthenticationProviders.h>
#import <MASFoundation/MASAuthenticationProvider.h>
#import <MASFoundation/MASConfiguration.h>
#import <MASFoundation/MASMessage.h>
#import <MASFoundation/MASDevice.h>
#import <MASFoundation/MASFile.h>
#import <MASFoundation/MASApplication.h>
#import <MASFoundation/MASGroup.h>
#import <MASFoundation/MASUser.h>
#import <MASFoundation/MASSessionSharingQRCode.h>
Constants are meant to be used 1) for easy reproduction of commonly used values in multiple places in same or multiple classes and 2) to avoid insertion of hard coded values in the implementation file.
For contant values that will be publicly available, place constants in MASConstant.h
file; otherwise, place constants in MASConstantsPrivate.h
files.
For constants syntax, always declare the variable as a static
constant and avoid using #define
unless it is meant to be used as a macro.
For example:
static NSString *const MASPublicConstantValue = @"MASPublicConstantValue";
Not:
#define MASAvoidUsingThisConstant @"MASAvoidUsingThisConstant"
- Use consistent spacing format across all places in the code.
- For indentation, use 4 spaces. In
Xcode's preference > Text Editing > Indentation
, Tab and indent 4 spaces (default value).
- For methods, properties, and class documentation, use VVDocumenter to ensure consistency for documentation styles.
For example:
- Method
/**
* Sets the MASDeviceRegistrationType property. The default is MASDeviceRegistrationTypeClientCredentials.
*
* @param registrationType The MASDeviceRegistrationType.
*/
+ (void)setDeviceRegistrationType:(MASDeviceRegistrationType)registrationType;
- Property
/**
* The class name of the object.
*/
@property (nonatomic, readonly, copy) NSString *className;
- Add an in-line comment above the line of code
- Add in-line comments to ensure understanding for other developers
- Use leading and trailing empty in-line comment,
//
- Add 1 space between the comments and in-line comment section
For example:
//
// Place an in-line comment like this
//
Not:
//Don't do in-line comment like this
- Spaces should be added for each word and
*
andproperty name
should not have a space.
For examples:
- Property
@property (nonatomic, copy, readwrite) NSString *userName;
- Enum
typedef NS_ENUM(NSInteger, MASDeviceRegistrationType)
Not:
@property(nonatomic, copy,readwrite) NSString*userName;
- Use 2 new lines between each property declaration and 1 new line for the first property in
pragma mark section
in.h
file. And use proper documentation for the description of the property.
For examples:
///--------------------------------------
/// @name Managing Object Properties
///--------------------------------------
# pragma mark - Managing Object Properties
/**
* The class name of the object.
*/
@property (nonatomic, readonly, copy) NSString *className;
/**
* The id of the object.
*/
@property (nonatomic, readonly, copy) NSString *objectId;
///--------------------------------------
/// @name MAS Constants
///--------------------------------------
# pragma mark - MAS Constants
/**
* The enumerated MASRegistrationTypes.
*/
typedef NS_ENUM(NSInteger, MASDeviceRegistrationType)
{
/**
* Unknown encoding type.
*/
MASDeviceRegistrationTypeUnknown = -1,
/**
* The client credentials registration type.
*/
MASDeviceRegistrationTypeClientCredentials,
...
...
};
/**
* The enumerated MASRequestResponseTypes that can indicate what data format is expected
* in a request or a response.
*/
typedef NS_ENUM(NSInteger, MASRequestResponseType)
{
...
...
Not:
///--------------------------------------
/// @name Managing Object Properties
///--------------------------------------
# pragma mark - Managing Object Properties
/**
* The class name of the object.
*/
@property (nonatomic, readonly, copy) NSString *className;
/**
* The id of the object.
*/
@property (nonatomic, readonly, copy) NSString *objectId;
- Use 1 space after the method scope and between the method segments.
- Use 1 space between
object type
and*
for every parameter and return type of the method if needed.
For example:
+ (void)start:(MASCompletionErrorBlock)completion;
+ (MASObject *)currentObject;
- (void)setObject:(id)object forKeyedSubscript:(id <NSCopying>)key;
Not:
+ (void)start: (MASCompletionErrorBlock)completion;
+(MASObject*)currentObject;
-(void)setObject:(id)object forKeyedSubscript:(id<NSCopying>)key;
- Use 3 new lines between each method declarations and 1 new line for the first property in
pragma mark section
in.h
file. - Use 2 new lines between each method declarations and 1 new line for the first property in
pragma mark section
in.m
file. - Opening and closing braces for method implementation should always be in newline.
- All private methods that are not present in
.h
file should also be documented in.m
file with same documentation format.
For example: (.h file)
///--------------------------------------
/// @name Accessors
///--------------------------------------
# pragma mark - Accessors
/**
* Returns the value associated with a given key.
*
* @param key The given identifying key for which to return the corresponding value.
*
* @return The value associated with a given key.
*/
- (id)objectForKey:(id)key;
/**
* Sets the object associated with a given key.
*
* @param object The object for `key`. A strong reference to the object is maintaned by MASObject.
* Raises an `NSInvalidArgumentException` if `object` is `nil`.
* If you need to represent a `nil` value - use `NSNull`.
*
* @param key The key for `object`. Raises an `NSInvalidArgumentException` if `key` is `nil`.
*/
- (void)setObject:(id)object forKey:(id <NSCopying>)key;
For example: (.m file)
#pragma mark - pragma section
- (id)objectForKey:(id)key
{
...
return object;
}
- (void)setObject:(id)object forKey:(id <NSCopying>)key
{
...
}
- Use 1 space in between control statement and bracket as well as properties and operator.
- Opening brace should always be in new line for first
if
statement, otherelse
orelse if
's opening brace should be placed in the same line. - Closing brace should always be in new line.
- Opening and closing brace should always be included even for one line of code in the statement.
For example:
if (isBoolean)
{
...
}
else {
}
if (isBoolean && isNotBoolean && [[MASObject currentObject] isBoolean])
{
...
}
else if (otherBoolean) {
...
}
if (isBoolean)
{
counter++;
}
switch (type) {
//
// Configuration
//
case MASSwitchValue:
value = @"value";
break;
//
// Default
//
default:
value = @"default";
break;
}
for (NSString *stringObj in objects)
{
...
}
Not:
if(isBoolean){
...
}else{
}
if (isBoolean && isNotBoolean&& [[MASObject currentObject]isBoolean]){
...
} else if(otherBoolean)
{
...
}
if (isBoolean) counter++;
switch(type){
case MASSwitchValue:
value = @"value";
break;
default:
value = @"default";
break;
}
for(NSString *stringObj in objects){
...
}
Because we want to support Swift with bridge header, please be aware of Nullability while writing codes in Objective-C. In Objective-C, Nullability does not make any difference, but it will make a difference when developers are using our framework in Swift.
Use _Nullable
and _Nonnull
type annotation in properties and methods.
For example:
@property (copy, nullable) NSString *name;
@property (copy, readonly, nonnull) NSDictionary *thisDictionary;
For more detail, see this blog post
Because we are maintaining multiple frameworks, ensure that all frameworks use the same style, format, and file structure.
For any new files or folder (groups in xCode), use the following folder structure.
- Framework name folder (i.e. MASFoundation, MASUI, MASConnecta)
-- Framework public header file
-- Class (Folder)
--- categories
--- models
--- _private_
---- categories
---- services
---- models
-- Vender
- All public files should be located under
Classes
,categories (under Classes)
andmodels (under Classes)
. - All private files should be located under
categories
,services
,models
, or any other folders under_private
folder. - When making a new group in Xcode, create an actual directory in file system, and add the directory into the project as group.
- If third-party libraries are being used, include them in the
Vendor
folder. - It is recommended to rename the prefix of third-party libraries to avoid any conflict with other developers' project which may use the same library.
- Verify that you have a valid third-party library license, and that you are allowed to use it.
- All classes should start with the prefix,
MAS
, except for the category class from iOS SDK or other vendors.
- For a newly created model class, the class should be inherited from
MASObject.h
. - For a newly created service class, the class should be inherited from
MASService.h
. - For a class used in two or more frameworks, a model of the class must be created in
MASFoundation
and a category of the class in the specific framework.
When you create a new service class, make sure to implement a service class that is inherited from MASService
.
- Define a constant in
MASConstantsPrivate.h
class with a uniquely generated UUID. - When you are creating a service class in an external framework outside of
MASFoundation
, include the UUID inMASConstantsPrivate.h
and use the same UUID value in the external service class'+ (NSString *)serviceUUID
property.
For example:
+ (NSString *)serviceUUID
{
// DO NOT change this without a corresponding change in MASFoundation
return @"8b66aaa4-efbf-11e5-9ce9-5e5517507c66";
}
- For a newly created
viewController
class, the class should be inherited fromMASViewController.h
.
For public category classes, specify the name using the framework name. If the category is not public, use the framework name and the word Private
in the end. Privates categories must be created under the _private_
folder.
For example:
// For public category class
@interface NSData (MASFoundation)
// For private category class. Must reside inside the _private_ folder
@interface MASUser (MASFoundationPrivate)
All frameworks handle errors with proper framework error domains.
In MASConstants, or any framework constant file, properly define the error domain constants. The error domain format should be com.ca.FRAMEWORKNAME:SUB_DOMAIN.
For example:
// The NSString error domain used by all MAS server related Foundation level NSErrors.
static NSString *const MASFoundationErrorDomain = @"com.ca.MASFoundation:ErrorDomain";
// The NSString error domain used by all MAS local level NSErrors.
static NSString *const MASFoundationErrorDomainLocal = @"com.ca.MASFoundation.localError:ErrorDomain";
// The NSString error domain used by all target API level NSErrors.
static NSString *const MASFoundationErrorDomainTargetAPI = @"com.ca.MASFoundation.targetAPI:ErrorDomain";