Objective-C 代码规范

这份编码规范将应用到公司内部编码约定

背景

以下是Apple 提供了一些指南以及参考其他编码的指南

语言

所有代码的编写、文件夹命名和项目命名全部使用英文禁止使用拼音及中文

推荐:

UIView *backgroundView = [[UIView alloc]init];

不推荐:

UIView *beijing = [[UIView alloc]init];

代码块标记

使用#pragma mark -规范。试用于一般的类文件中包含协议和代理

#pragma mark - 生命周期

- (instancetype)init {}
- (void)dealloc {}
- (void)viewDidLoad {}
- (void)viewWillAppear:(BOOL)animated {}
- (void)didReceiveMemoryWarning {}

#pragma mark - 自定义属性方法实现set/get

- (void)setCustomProperty:(id)value {}
- (id)customProperty {}

#pragma mark - IB 触发事件

- (IBAction)submitData:(id)sender {}

#pragma mark - 公用接口/属性

- (void)publicMethod {}

#pragma mark - 私有接口/属性

- (void)privateMethod {}

//代理说明及代理方法的实现标记
#pragma mark - Protocol conformance
#pragma mark - UITextFieldDelegate
#pragma mark - UITableViewDataSource
#pragma mark - UITableViewDelegate

#pragma mark - NSCopying

- (id)copyWithZone:(NSZone *)zone {}

#pragma mark - NSObject

- (NSString *)description {}

间距(空格/tab)及换行

  • 使用系统默认的制表符(4个空格)
  • 方法第一个括号和代码保持同一行禁止换行
  • 方法参数超过两个以上使参数换行保持对齐

推荐:

if(user.isHappy){
   //做某事 
} else {
   //做某事 
}

不推荐:

if(user.isHappy){
   //做某事 
}
else{
   //做某事 
}
if(user.isHappy)
{
   //做某事 
}else
{
   //做某事 
}

建议:

// blocks are easily readable
[UIView animateWithDuration:1.0 animations:^{
  // something
} completion:^(BOOL finished) {
  // something
}];

不建议:

// colon-aligning makes the block indentation hard to read
[UIView animateWithDuration:1.0
                 animations:^{
                     // something
                 }
                 completion:^(BOOL finished) {
                     // something
                 }];
  • -、+ 于方法之间保留一个空格 { 之前保留一个空格
  • 一元运算不保留空格,二元运算于运算符前后保持一个空格

事例:

NSInteger index = rand() % 50 + 25; // arc4random_uniform(50) should be used insted of `rand() % 50`, but doesn't illustrate the principle well
index++;
index += 1;
index--;

注释

尽可能的使用Xcode只带注释快捷键。关键代码尽量做到注视清晰明了。代码块尽量保持足够小。功能设计足够单一这样能够减少写注释。

命名

尽量使用苹果的命名规范特别是内存管理的约定 (NARC). 命名尽量清晰且足够长。可以节省不必要的注释。以下是苹果官方命名指南 这里

建议:

UIButton *settingsButton;

不建议:

UIButton *setBut;
  • 类名及常量名称使用前缀ZJD
  • 文件名首字母大写驼峰命名。
  • 其他变量及方法应以小写字母开头驼峰命名。
  • 类别Category 扩展系统类所有方法都应该加上前缀。私有类可以选择行处理

建议:

static NSTimeInterval const ZJDTutorialViewControllerNavigationFadeAnimationDuration = 0.3;

不建议:

static NSTimeInterval const fadetime = 1.7;

实例变量

尽量少的使用实力变量。如有必要建议优先使用私有属性。访问内部属性时set 尽量使用self. 保持代码的一直性。 所有的局部变量都不允许 _ 开头来命名。

方法

在创建方法中(对象- 、类方法+)方法中 (-、 +)应该和 () 括号保持一个空格的距离。方法中尽量使用传值而不是使用属性或实力变量。在传值过程中尽量标明类型。应避免使用id类型。

建议:

- (void)setExampleText:(NSString *)text image:(UIImage *)image;
- (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;
- (id)viewWithTag:(NSInteger)tag;
- (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height;

不建议:

-(void)setT:(NSString *)text i:(UIImage *)image;
- (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;
- (id)taggedView:(NSInteger)tag;
- (instancetype)initWithWidth:(CGFloat)width andHeight:(CGFloat)height;
- (instancetype)initWith:(int)width and:(int)height;  // Never do this.

点语法

应该尽量多的使用点语法来访问set/和get 方法。这样能够保证代码的紧凑和整洁。类方法禁止使用点语法。 这里是属性关键词的描述其他情况下还是尽量使用[];

推荐:

NSInteger arrayCount = [self.array count];
view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;

不推荐:

NSInteger arrayCount = self.array.count;
[view setBackgroundColor:UIColor.orangeColor];
UIApplication.sharedApplication.delegate;

字面量初始化

NSString, NSDictionary, NSArray, 和 NSNumber 创建这些不可变对象的时候尽量小心。因为不能传入 nil 值, 创建 NSArrayNSDictionary 如果传入空值会引起崩溃。字面量创建可是使用系统编译器的检查不容易出现空值。

推荐:

NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone": @"Kate", @"iPad": @"Kamal", @"Mobile Web": @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingStreetNumber = @10018;

不推荐:

NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil];
NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil];
NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];
NSNumber *buildingStreetNumber = [NSNumber numberWithInteger:10018];

常量

应该尽量少的使用宏来创建常量。宏会影响编译速度。应该使用static const 来创建常量。 避免使用#define来创建常量;

推荐:

static NSString * const RWTAboutViewControllerCompanyName = @"RayWenderlich.com";

static CGFloat const RWTImageThumbnailHeight = 50.0;

不推荐:

#define CompanyName @"RayWenderlich.com"

#define thumbnailHeight 2

枚举类型

根据苹果官方推荐创建枚举应使用NS_ENUM & NS_OPTIONS 而不该使用enum 。因为NS_ENUM & NS_OPTIONS具有类型检查。关于更详细的介绍推荐看这里

推荐:

typedef NS_ENUM(NSInteger, RWTLeftMenuTopItemType) {
  RWTLeftMenuTopItemMain,
  RWTLeftMenuTopItemShows,
  RWTLeftMenuTopItemSchedule
};
typedef NS_ENUM(NSInteger, RWTGlobalConstants) {
  RWTPinSizeMin = 1,
  RWTPinSizeMax = 5,
  RWTPinCountMin = 100,
  RWTPinCountMax = 500,
};

不推荐:

enum GlobalConstants {
  kMaxPinSize = 5,
  kMaxPinCount = 500,
};

逻辑判断

在if 判断的语句中如果可以一行写完。就使用一行。这样可以大大提高代码的紧凑和可读性。更不会浪费两行空间。这里有关于是否使用大括号的一个讨论
推荐:

if (!goodCondition) return;

if (condition == YES) {
    // do stuff
} else {
    // do other stuff
}

不推荐:

if (!error)
  return success;

三元运算

只有能够提升代码整洁性的时候可以使用。过多的使用会提高复杂度。只能使用一层,其他情况应使用if语句。

推荐:

NSInteger value = 5;
result = (value != 0) ? x : y;

BOOL isHorizontal = YES;
result = isHorizontal ? x : y;

不推荐:

result = a > b ? x = c > d ? c : d : y;

初始化方法

这里推荐使用苹果初始化模版,返回值使用instancetype而不是id。类方法的初始化参考这里

- (instancetype)init {
  self = [super init];
  if (self) {
    // ...
  }
  return self;
}
@interface Airplane
+ (instancetype)airplaneWithType:(RWTAirplaneType)type;
@end

CGRect 函数

在访问x, y, width, 和 height 中建议使用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 = CGRectMake(0.0, 0.0, width, height);

不推荐:

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;
CGRect frame = (CGRect){ .origin = CGPointZero, .size = frame.size };

黄金路径

如下面的事例,左边的空格位置被称为黄金路径。当然是空格越少越好,说明你的代码逻辑控制比较清晰。多使用return,这样可以避免大量的if嵌套

推荐:

- (void)someMethod {
  if (![someOther boolValue]) {
    return;
  }

  //做你想做的事
}

不推荐:

- (void)someMethod {
  if ([someOther boolValue]) {
    //做你想做的事
  }
}

单例

创建单例的时候要保证线程安全。来在整个应用周期中共享。所以苹果推出了创建单例的模版,如果不这样做来创建单例有可能出现意外的崩溃;

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

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

  return sharedInstance;
}

阿振

谦虚地说着“献丑”,却往往献出了最珍贵的东西。你永远不知道,这句口是心非,需要多么大的努力!

相关推荐