iOS Objective-C 编码规范

2017-08-13  本文已影响61人  buptwsg

这份规范指南概括了本 iOS 团队的代码约定。

目录

源文件排版

1.缩进

2.空格

3.大括号

4.空行和换行

5.导入

如果有一个以上的 import 语句,就对这些语句进行分组。每个分组的注释是可选的。
注:对于模块使用@import语法。

// Frameworks
@import QuartzCore;

// Models
#import "NYTUser.h"

// Views
#import "NYTButton.h"
#import "NYTUserView.h"

6.将代码分组

推荐:

int x = 0;
x += 1;

if (x < 2 && y < 3) {
}

for (int k = 0; k < 10; k++) {
}

- (void)setExampleText:(NSString *)text image:(UIImage *)image;

if (user.isHappy) {
    // Do something
}
else {
    // Do something else
}

@interface NYTSection: NSObject<UITableViewDataSource, UITableViewDelegate>

@property (copy, nonatomic) NSString *headline;

@end

命名

1.语言

2.前缀

3.变量(属性,实例变量,局部变量)

4.方法

5.通知

通知的命名格式为:[类名] + [Did | Will] + [描述] + Notification
例子:

UIApplicationDidEnterBackgroundNotification
NSApplicationDidBecomeActiveNotification
NSWindowDidMiniaturizeNotification
NSTextViewDidChangeSelectionNotification

6.异常

异常的命名格式为:[Prefix] + [UniquePartOfName] + Exception
例子:

NSColorListIOException
NSColorListNotEditableException
NSDraggingException
NSFontUnavailableException
NSIllegalSelectorException

常量,全局量,静态量

.h:
extern NSString * const RWTAboutViewControllerCompanyName;
extern CGFloat const RWTImageThumbnailHeight;
extern BOOL gRWTEnableHardwareEncoding;

.m:
NSString * const RWTAboutViewControllerCompanyName = @"RayWenderlich.com";
CGFloat const RWTImageThumbnailHeight = 50.0;
BOOL gRWTEnableHardwareEncoding = YES;

static NSInteger const RWTMaxNameLength = 20;

代码的文档化

参考文章:https://www.raywenderlich.com/66395/documenting-in-xcode-with-headerdoc-tutorial
使用HeaderDoc规范来写代码的文档,可以使得我们能够象查看官方文档一样,查看自己的代码的文档,而不必跳转到对方的头文件去查看注释。

1.选择注释符号

2.使用Tags

3.示例

@interface MathAPI : NSObject

/*!
 * @discussion A really simple way to calculate the sum of two numbers.
 * @param firstNumber An NSInteger to be used in the summation of two numbers
 * @param secondNumber The second half of the equation.
 * @warning Please make note that this method is only good for adding non-negative numbers.
 * @return The sum of the two numbers passed in.
 */
+ (NSInteger)addNumber:(NSInteger)firstNumber toNumber:(NSInteger)secondNumber;

@end
/*!
 * @enum CarType
 * @brief A list of newer car types.
 * @constant CarTypeHatchback 
                        Hatchbacks are fun, but small.
 * @constant CarTypeSedan
                        Sedans should have enough room to put your kids, and your golf clubs
 * @constant CarTypeEstate
                        Estate cars should hold your kids, groceries, sport equipment, etc.
 * @constant CarTypeSport
                        Sport cars should be fast, fun, and hard on the back.
*/
typedef NS_ENUM(NSInteger, CarType){
    /// Hatchbacks are fun, but small.
    CarTypeHatchback,
    
    /// Sedans should have enough room to put your kids, and your golf clubs
    CarTypeSedan,
    
    /// Estate cars should hold your kids, groceries, sport equipment, etc.
    CarTypeEstate,
    
    /// Sport cars should be fast, fun, and hard on the back.
    CarTypeSport
};

/*!
 * @typedef Old Car Types
 * @brief A list of older car types.
 * @constant OldCarTypeModelT A cool old car.
 * @constant OldCarTypeModelA A sophisticated old car.
 */
typedef enum {
    OldCarTypeModelT,
    OldCarTypeModelA
} OldCarType;

/*!
 * @brief A block that makes the car drive.
 * @param distance The distance is equal to a distance driven when the block is ready to execute. It could be miles, or kilometers, but not both. Just pick one and stick with it. ;]
 */
typedef void(^driveCompletion)(CGFloat distance);

@interface Car : NSObject

@property (nonatomic) UIColor *exteriorColor;

@property (nonatomic) NSString *nickname;

/// Indicates the kind of car as enumerated in the "CarType" NS_ENUM
@property (nonatomic, assign) CarType carType;

/*!
 * @brief The car will drive, and then execute the drive block
 * @param completion A driveCompletion block
 * @code [car driveCarWithCompletion:^(CGFloat distance){
     NSLog(@"Distance driven %f", distance);
 }];
 */
- (void)driveCarWithCompletion:(driveCompletion)completion;

@end

Objective-C 最佳实践

1.点语法

2.使用模板的写法

3. init方法或是类的工厂方法中,使用instancetype作为返回类型

目的是为了提高类型安全,在编译器就可以发现错误的函数调用。

4. 使用NS_DESIGNATED_INITIALIZER来标识指定的初始化函数

5.使用新式语法

6.类的属性声明

7.枚举和位域的定义

typedef NS_ENUM(NSInteger, UIViewAnimationCurve) {
    UIViewAnimationCurveEaseInOut,         // slow at beginning and end
    UIViewAnimationCurveEaseIn,            // slow at beginning
    UIViewAnimationCurveEaseOut,           // slow at end
    UIViewAnimationCurveLinear,
};
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};

8.使用nonnull, nullable来修饰函数的参数或是类的属性

加上此类修饰符,可以提高代码的可读性,调用者不需要查看源代码,就可以明白设计者的意图,并据此传递正确的参数。
如果对一个nonnull修饰的参数或是属性,传入一个nil参数,那么在输入代码以后,IDE就可以给出警告,这样就可以第一时间发现问题。

9.访问数组元素时要小心出现下标越界的错误

10.检查参数是否为nil的几种情况

11.单例

单例对象应该使用线程安全的模式创建共享的实例。

+ (instancetype)sharedInstance {
    static id sharedInstance = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });

    return sharedInstance;
}

12.使用CGRect函数

当访问一个 CGRectxywidthheight 时,应该使用CGRect相关的函数代替直接访问结构体成员。苹果的 CGGeometry 参考中说到:

All functions described in this reference that take CGRect data structures as inputs implicitly standardize those rectangles before calculating their results. For this reason, your applications should avoid directly reading and writing the data stored in the CGRect data structure. Instead, use the functions described here to manipulate rectangles and to retrieve their characteristics.

推荐:

CGRect frame = self.view.frame;

CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);

反对:

CGRect frame = self.view.frame;

CGFloat x = frame.origin.x;
CGFloat y = frame.origin.y;
CGFloat width = frame.size.width;
CGFloat height = frame.size.height;

13.错误处理

当引用一个返回错误参数(error parameter)的方法时,应该针对返回值,而非错误变量。

推荐:

NSError *error;
if (![self trySomethingWithError:&error]) {
    // 处理错误
}

反对:

NSError *error;
[self trySomethingWithError:&error];
if (error) {
    // 处理错误
}

14.头文件中要尽可能少的import其它的头文件

Xcode 工程

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[self performSelector:sel withObject:arguments];
#pragma clang diagnostic pop
上一篇 下一篇

猜你喜欢

热点阅读