iOS学习开发iOS Developer

iOS编码规范

2017-06-03  本文已影响252人  Dombo_Y

面试被问到公司编码规范问题,感觉有很多东西,但是不知道该怎么说出来,今天突然找到 李明杰 老师的一份编码规范。重新又看一遍觉得受益良多。

关于命名的一般性的原则

Xcode配置

文件扩展名

.h  C/C++/Objective-C header file
.m  Objective-C implementation file
.mm Objective-C++ implementation file
.cc Pure C++ implementation file
.c  C implementation file

声明孤立的类或协议:

将孤立的类或协议声明放置在单独的头文件中,该头文件名称与类或协议同名。

声明相关联的类或协议:

将相关联的声明(类,类别及协议) 放置在一个头文件中,该头文件名称与主要的类/类别/协议的名字相同。

NsString.h NSString 和 NSMutableString 类
NsLock.h NSLocking 协议和 NSLock, NSConditionLock, NSRecursiveLock 类

为已有框架中的某个类扩展 API:

如果要在一个框架中声明属于另一个框架某个类的范畴类的方法,该头文件的命名形式为:原类名+“Additions”。如 Application Kit 中的 NSBundleAdditions.h。
相关联的函数与数据类型:将相联的函数,常量,结构体以及其他数据类型放置到一个头文件中,并以合适的名字命名。如 Application Kit 中的 NSGraphics.h。
工程中的group与本地文件夹要一一对应
类及协议

采用Pascal命名方式

采用Camel命名方式

  Objective-C
  - (void) invokeWithTarget:(id)target:
  - (void) selectTabViewItem:(NSTableViewItem *)tableViewItem
get属性方法不要带get前缀,也不要带其它前缀

  Objective-C
  - (NSSize) cellSize;  对
  - (NSSize) calcCellSize;  错
  - (NSSize) getCellSize;  错
参数要用描述该参数的标签命名

  Objective-C
  - (void) sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;  对
  - (void) sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;  错
第一个参数,方法名要能描述该参数

  Objective-C
  - (id) viewWithTag:(int)aTag;  对
  - (id) taggedView:(int)aTag;  错
不要使用 and 来连接用属性作参数标签,虽然上面的例子中使用 add 看起来也不错,但当你方法有太多参数关键字时就有问题。

  Objective-C
  - (int) runModalForDirectory:(NSString *)path file:(NSString *)name types:(NSArray *)fileTypes;  对
  - (int) runModalForDirectory:(NSString *)path addFile:(NSString *)name addTypes:(NSArray *)fileTypes;  错
如果方法描述两种独立的行为,使用 and 来串接它们

  Objective-C
  - (BOOL) openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL)flag; NSWorkspace 
方法的参数个数尽量保持四个以内,如果需要超过四个的参数,应该考虑重构方法或者抽象参数为类型

方法的实现需要进行参数有效性检查;

在方法声明中,在(-/+)符号与返回值之间留1个空格。此外,参数与前面的冒号不留空,方法段与之间留1个空格
方法间保持一个空行
方法内的空行用于区分不同的功能代码,但是如果方法中又太多的功能区块那么需要考虑重构代码
不要使用冒号对齐含实现块的方法,因为Xcode的缩进会使代码更难读

推荐:

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

不推荐:

  Objective-C
  // colon-aligning makes the block indentation hard to read
  [UIView animateWithDuration:1.0
             animations:^{
                 // something
             }
             completion:^(BOOL finished) {
                 // something
             }];

访问方法

如果属性是用名词描述的,则命名格式为

  Objective-C
  - (void) setNoun:(type)aNoun;
  - (type) noun;
例如:

  Objective-C
  - (void) setgColor:(NSColor *)aColor;
  - (NSColor *) color;
如果属性是用形容词描述的,则命名格式为:

  Objective-C
  - (void) setAdjective:(BOOL)flag;
  - (BOOL) isAdjective;
例如:

  Objective-C
  - (void) setEditable:(BOOL)flag;
  - (BOOL) isEditable;
如果属性是用动词描述的,则命名格式为:(动词要用现在时时态)

  Objective-C
  - (void) setVerbObject:(BOOL)flag;
  - (BOOL) verbObject;
例如:

  Objective-C
  - (void) setShowAlpha:(BOOL)flag;
  - (BOOL) showsAlpha;
不要使用动词的过去分词形式作形容词使用

  Objective-C
  - (void) setAcceptsGlyphInfo:(BOOL)flag;  对
  - (BOOL) acceptsGlyphInfo;  对
  - (void) setGlyphInfoAccepted:(BOOL)flag;  错
  - (BOOL) glyphInfoAccepted;  错
可以使用情态动词(can, should, will 等)来提高清晰性,但不要使用 do 或 does

  Objective-C
  - (void) setCanHide:(BOOL)flag;  对
  - (BOOL) canHide;  对
  - (void) setShouldCloseDocument:(BOOL)flag;  对
  - (void) shouldCloseDocument;  对
  - (void) setDoseAcceptGlyphInfo:(BOOL)flag;  错
  - (BOOL) doseAcceptGlyphInfo;  错
方法调用时,如果参数太多,则遵照以下方式

  Objective-C
  [myObject doFooWith:arg1  
                 name:arg2  
                error:arg3];  
禁用以下方式

  Objective-C
  [myObject doFooWith:arg1 name:arg2  // some lines with >1 arg
                error:arg3];

  [myObject doFooWith:arg1
                 name:arg2 error:arg3];

  [myObject doFooWith:arg1
            name:arg2  // aligning keywords instead of colons
            error:arg3];
如果无法使用冒号对齐,则如下缩进两个空格

  Objective-C
  [myObj short:arg1
    longKeyword:arg2
    evenLongerKeyword:arg3];
委托方法 委托方法是那些在特定事件发生时可被对象调用,并声明在对象的委托类中的方法。它们有独特的命名约定,这些命名约定同样也适用于对象的数据源方法。

名称以标示发送消息的对象的类名开头,省略类名的前缀并小写类第一个字符

  Objective-C
  - (BOOL) tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
  - (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;
冒号紧跟在类名之后(随后的那个参数表示委派的对象)。该规则不适用于只有一个 sender 参数的方法

  Objective-C
  - (BOOL) applicationOpenUntitledFile:(NSApplication *)sender;
上面的那条规则也不适用于响应通知的方法。在这种情况下,方法的唯一参数表示通知对象

  Objective-C
  - (void) windowDidChangeScreen:(NSNotification *)notification;
用于通知委托对象操作即将发生或已经发生的方法名中要使用 did 或 will

  Objective-C
  - (void) browserDidScroll:(NSBrowser *)sender;
  - (NSUndoManager *) windowWillReturnUndoManager:(NSWindow *)window;
用于询问委托对象可否执行某操作的方法名中可使用 did 或 will,但最好使用 should

  Objective-C
  - (BOOL) windowShouldClose:(id)sender;
方法参数

不要在参数名中使用 pointer 或 ptr,让参数的类型来说明它是指针
避免使用 one, two,...,作为参数名,更不要用1,2,...
避免为节省几个字符而缩写
采用以下参数标签与参数组合的惯例

   Objective-C
  ...action:(SEL)aSelector
  ...alignment:(int)mode
  ...atIndex:(int)index
  ...content:(NSRect)aRect
  ...doubleValue:(double)aDouble
  ...floatValue:(float)aFloat
  ...font:(NSFont *)fontObj
  ...frame:(NSRect)frameRect
  ...intValue:(int)anInt
  ...keyEquivalent:(NSString *0charCode
  ...length:(int)numBytes
  ...point:(NSPoint)aPoint
  ...stringValue:(NSString *)aString
  ...tag:(int)anInt
  ...target:(id)anObject
  ...title:(NSString *)aString 

常量及枚举

  Objective-C
  typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
      UITableViewCellStyleDefault,
      UITableViewCellStyleValue1,
      UITableViewCellStyleValue2,
      UITableViewCellStyleSubtitle
  };
定义位与枚举使用NS_OPTION,命名方式为:前缀+Pascal命名+Mask
  Objective-C
  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
  };
const常量命名方式:前缀+Pascal命名

属性和变量

  Objective-C
  view.backgroundColor = [UIColor orangeColor];
  [UIApplication sharedApplication].delegate;
而不是

  Objective-C
  [view setBackgroundColor:[UIColor orangeColor]];
 UIApplication.sharedApplication.delegate;

最好使用auto-synthesis。但是,如果有必要,@synthesize和@dynamic应各自在实现的新行定义

当使用属性,实例变量时应该使用self.来访问,这意味着所有的属性将很容易区分,因为它们都使用 self. 开头声明指针时星号应该靠近变量名

import和include

用#import 导入Objective-C或Objective-C++头文件,用#include 导入C或C++头文件;
导入框架根的头文件而不是分别导入框架头文件,

  Objective-C
  #import <Foundation/Foundation.h>     // good
  #import <Foundation/NSArray.h>        // avoid
  #import <Foundation/NSString.h>
  ...

前缀

前缀有规定的格式。它由两到三个大写字符组成,不能使用下划线与子前缀
前缀 Cocoa 框架
NS Foundation
NS Application Kit
AB Address Book
IB Interface Builder

命名 class,protocol,structure,函数,常量时使用前缀;
命名成员方法时不使用前缀,因为方法已经在它所在类的命名空间中;
同理,命名结构体字段时也不使用前缀

Blocks VS Selectors VS Protocols

  Objective-C
  returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};
  @property (nonatomic, copy) returnType (^blockName)(parameterTypes);
- (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;
  [someObject someMethodThatTakesABlock:^returnType (parameters) {...}];
  typedef returnType (^TypeName)(parameterTypes);
  TypeName blockName = ^returnType(parameters) {...};
NSException

同样的如C++中一样,强烈不建议使用异常
如果非要使用,代码格式如下

  Objective-C
  @try {
    foo();
  }
  @catch (NSException *ex) {
    bar(ex);
  }
  @finally {
    baz();
  }

异常由具有如下形式的全局 NSString 对象标识: [Prefix] + UniquePartOfName + Exception UniquePartOfName 部分是有连续的首字符大写的单词组成。例如:

NSColorListIOException NSColorListNotEditableException NSDraggingException NSFontUnavailableException NSIllegalSelectorException

初始化函数

  Objective-C
  NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve"];
  NSDictionary *productManagers = @{@"iPhone" : @"Kate", @"iPad" : @"Kamal"};
  NSNumber *shouldUseLiterals = @YES;
  NSNumber *buildingZIPCode = @10018;

而不是

  Objective-C
  NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", nil];
  NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys:@"Kate", @"iPhone", @"Kamal",     @"iPad", nil];
  NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];
  NSNumber *buildingZIPCode = [NSNumber numberWithInteger:10018];
在初始化函数中,访问数据成员应该直接访问实例变量而不是属性

pragma

  Objective-C
  @implementation ViewController
  - (instancetype)init {
    ...
  }
  
  #pragma mark - UIViewController
  - (void)viewDidLoad {
    ...
  }

  #pragma mark - IBAction
  - (IBAction)cancel:(id)sender {
    ...
  }

  #pragma mark - UITableViewDataSource
  - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    ...
  }

  #pragma mark - UITableViewDelegate
  - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    ...
  }
nil / Nil / NULL / NSNull

Objective-C中默认所有的指针指向nil
nil最显著的行为是,它虽然为零,仍然可以有消息发送给它,结果返回0

Objective-C
// 举个例子,这个表达...
if (name != nil && [name isEqualToString:@"Steve"]) { ... }
// …可以被简化为:
if ([name isEqualToString:@"steve"]) { ... }
不需要显示初始化为nil,更不要初始化为其它几个关键词

需要知道如下

Symbol  Value   Meaning
NULL    (void *)0   literal null value for C pointers
nil (id)0   literal null value for Objective-C objects
Nil (Class)0    literal null value for Objective-C classes
NSNull  [NSNull null]   singleton object used to represent null
注释

表达式格式

方法大括号和其它大括号(比如for、if、while、switch等等)应在语句的同一行开始,而在新的一行关闭;

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

不要省略掉花括号,因为即使当前只有一行代码,可能后续其它人会添加代码,如果遗忘补上花括号会产生非预期结果

  Objective-C
  // good
  if (!error) {
      return success;
  }
  // bad
  if (!error)
      return success;
  // bad
  if (!error) return success;

Booleans

  Objective-C
  @property (assign, getter=isEditable) BOOL editable;
判断真假时不要与字面值比较

  Objective-C
  // good
  if (someObject) {
  }
  if (![anotherObject boolValue]) {
  }
  // bad
  if (someObject == nil) {}
  if ([anotherObject boolValue] == NO) {}
  if (isAwesome == YES) {} // Never do this.
  if (isAwesome == true) {} // Never do this.
Objective-C中的所有真值类型和数值:

Name    Typedef Header  True Value  False Value
BOOL    signed char objc.h  YES NO
bool    _Bool (int) stdbool.h   true    false
boolean unsigned char   MacTypes.h  TRUE    FALSE
NSNumber    __NSCFBoolean   Foundation.h    @(YES)  @(NO)
CFBooleanRef    struct  CoreFoundation.h    kCFBooleanTrue  kCFBooleanFalse

文档结构管理

上一篇 下一篇

猜你喜欢

热点阅读