objc 代码规范

1,160 阅读3分钟
原文链接: persenlee.github.io

目录

前言

​ 虽然编码规范是一件很个性化的事情,但是一个良好的代码规范是一种共识。下面的内容结合了参考文章以及个人的编码习惯而形成的规范。

行宽

尽量保持在100以内,具体设置如下

Xcode->Preferences->Text Editing->Page guide at column

类型

  • 使用到整形变量时,建议使用NSInteger NSUInteger,不建议使用int,uint 。
  • 使用float时,建议使用CGFloat

常量

建议

static NSString *const PLMessageCountChanageNotificationName = @"MessageCountChanageNotification"
static NSUInteger const PLRetryMaxCount = 5

不建议

#define PLMessageCountChanageNotificationName @"MessageCountChanageNotification"
#define PLRetryMaxCount 5

变量

  • 遵循驼峰模式即可
  • 对于实例变量建议以下划线开始命名
@interface Foo()
 {
    NSString *_name
 }
 @end

字面值

对于NSString, NSDictionary, NSArray,以及 NSNumber 支持语法糖

建议

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];

枚举

建议

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
    };

不建议

enum UIViewAnimationCurve {
  	UIViewAnimationCurveEaseInOut,         // slow at beginning and end
    UIViewAnimationCurveEaseIn,            // slow at beginning
    UIViewAnimationCurveEaseOut,           // slow at end
    UIViewAnimationCurveLinear,
    };

控制语句

关于if

建议

if(condition) {
  //...
  } else {
  //...
  }

不建议

if(condition)
{
  //..
  }
else
{
  //..
  }

关于switch

括号不是必须的,为了代码结构层次清晰,建议加上括号。

switch(condition){
  case 1:
  {
    //one line or multi-line
  }
  break;
  default:
  break;
  }

对于枚举类型的switch,可以不需要default

UIViewAnimationCurve curveType = UIViewAnimationCurveEaseInOut;
switch(curveType) {
  case UIViewAnimationCurveEaseInOut:
  {

  }
  break;
  case UIViewAnimationCurveEaseIn:
  {

  }
  break;
  case UIViewAnimationCurveEaseOut:
  {

  }
  break;
  case UIViewAnimationCurveLinear:
  {

  }
  break;
  }

关于for循环

对于集合类型(array,set) 建议使用 enumerateObjectsUsingBlock

NSArray *nameArray = @[@"Kita","jonas"];
[nameArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        //...
 }];

其次可以选择for in 如果不需要索引的话

for(NSString *name in nameArray) {
  //...
  }

属性

  • 对于属性修饰符要全都指示出来,对于纯量类型默认是(atomic,assign),对于对象类型默认是(atomic,strong)。权限修饰符默认readwrite可以不写,一般情况下属性都是readwrite,对于只读属性需要写明readonly
  • 对于有可变类型的类(NSString,NSArray,NSDictionary,NSSet) 建议使用copy,是因为有可能引用可变对象

建议

@property(nonatomic,copy) NSString *name;
@property(nonatomic,strong) UIView *containerView;

不建议

@property(nonatomic,strong) NSString *name;
@property(nonatomic) UIView *containerView;

方法

方法类型(-/+)后需要空一格

建议

- (void)setTitle:(nullable NSString *)title forState:(UIControlState)state;

不建议

-(void)setTitle:(nullable NSString *)title forState:(UIControlState)state;

注释

文件注释

注释是代码可读性的关键,最好的代码应该自成文档。

使用Xcode Snippets创建模板

模板建议

/**
 **<#文件内容的简要描述#>
 **<#代码作者#>
 **<#版权信息声明(如:Copyright 2008 Google Inc.)#>
 **<#必要的话,加上许可证样板。为项目选择一个合适的授权样板(例如,Apache 2.0, BSD, LGPL, GPL)。#>
 */

其他注释(类注释,方法注释等)

xcode8 建议使用自带注释快捷键 command+option+/

xcode8以下版本建议使用vvdocumenter注释插件

代码结构组织

#pragma mark - Lifecycle
- (instancetype)init {}
- (void)viewDidLoad {}
- (void)viewWillAppear:(BOOL)animated {}
- (void)didReceiveMemoryWarning {}
- (void)dealloc {}
#pragma mark - Getter
- (NSString *)name;
#pragma mark - Setter
- (void)setName:(NSString *)name;
#pragma mark - Public Methods
- (void)publicMethod {}
#pragma mark - Private Methods
- (void)privateMethod {}
#pragma mark - Some Delegate
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {}
#pragma mark - IBActions
- (IBAction)submitData:(id)sender {}

使用NSCAsserts作为断言

使用NSCAssert而不是assert 或者NSAssert

是因为NSAssert宏内部持有self,尤其在block中,极易引起retain cycle。

使用CGRect函数

建议

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 };

参考

dl.dropboxusercontent.com/s/5utnlwhr1…

github.com/raywenderli…

zh-google-styleguide.readthedocs.io/en/latest/g…