关于编程语言的所有规范,如果这里没有写到,那就在苹果的文档里:
应该 始终 使用点语法来访问或者修改属性,访问其他实例时首选括号。
推荐:
- view.backgroundColor = [UIColor orangeColor];
- [UIApplication sharedApplication].delegate;
反对:
- [view setBackgroundColor:[UIColor orangeColor]];
- UIApplication.sharedApplication.delegate;
/
- if
/
- else
/
- switch
等等)始终和声明在同一行开始,在新的一行结束。
- while
推荐:
- if (user.isHappy) {
- // Do something
- } else {
- // Do something else
- }
条件判断主体部分应该始终使用大括号括住来防止出错,即使它可以不用大括号(例如它只需要一行);
这些错误包括添加第二行(代码)并希望它是 if 语句的一部分时;
还有另外一种更危险的,当 if 语句里面的一行被注释掉,下一行就会在不经意间成为了这个 if 语句的一部分;
此外,这种风格也更符合所有其他的条件判断,因此也更容易检查。
推荐:
- if (!error) {
- return success;
- }
反对:
- if (!error)
- return success;
或
- if (!error) return success;
三目运算符,? ,只有当它可以增加代码清晰度或整洁时才使用。单一的条件都应该优先考虑使用。多条件时通常使用 if 语句会更易懂,或者重构为实例变量。
推荐:
- result = a > b ? x : y;
反对:
- result = a > b ? x = c > d ? c : d : y;
当引用一个返回错误参数(error parameter)的方法时,应该针对返回值,而非错误变量。
推荐:
- NSError *error;
- if (![self trySomethingWithError:&error]) {
- // 处理错误
- }
反对:
- NSError *error;
- [self trySomethingWithError:&error];
- if (error) {
- // 处理错误
- }
一些苹果的 API 在成功的情况下会写一些垃圾值给错误参数(如果非空),所以针对错误变量可能会造成虚假结果(以及接下来的崩溃)。
在方法签名中,在 -/+ 符号后应该有一个空格。方法片段之间也应该有一个空格。
推荐:
- - (void)setExampleText:(NSString *)text image:(UIImage *)image;
变量名应该尽可能命名为描述性的。除了
循环外,其他情况都应该避免使用单字母的变量名。
- for()
星号表示指针属于变量,例如:
不要写成
- NSString *text
或者
- NSString* text
, 常量除外。
- NSString * text
尽量定义属性来代替直接使用实例变量。
除了初始化方法(
,
- init
,等),
- initWithCoder:
方法和自定义的 setters 和 getters 内部,应避免直接访问实例变量。
- dealloc
推荐:
- @interface Model: NSObject
- @property(nonatomic,copy)NSString *name;
- @end
反对:
- @interface Model : NSObject {
- NSString *headline;
- }
- // *号应和实例变量在一起
- @property(nonatomic,copy)NSString * name;
- @property(nonatomic,copy)NSString* name;
当涉及到变量限定符时,
限定符 (
,
- __strong
,
- __weak
,
- __unsafe_unretained
) 应该位于星号和变量名之间,如:
- __autoreleasing
。
- NSString * __weak text
尽可能遵守苹果的命名约定,尤其那些涉及到,()的。
长的和描述性的方法名和变量名都不错。
推荐:
- UIButton *settingsButton;
反对:
- UIButton * setBut; // 不明确
属性和局部变量应该使用驼峰命名法并且首字母小写。
为了保持一致,实例变量应该使用驼峰命名法命名,并且首字母小写,以下划线为前缀。这与 LLVM 自动合成的实例变量相一致。
如果 LLVM 可以自动合成变量,那就让它自动合成。
推荐:
- @synthesize descriptiveVariableName = _descriptiveVariableName;
反对:
- id varnm;
当需要的时候,注释应该被用来解释 为什么 特定代码做了某些事情。所使用的任何注释必须保持最新否则就删除掉。
通常应该避免一大块注释,代码就应该尽量作为自身的文档,只需要隔几行写几句说明。这并不适用于那些用来生成文档的注释。
方法应该放在实现文件的最上面,并且刚好在
- dealloc
和
- @synthesize
语句的后面。在任何类中,
- @dynamic
都应该直接放在
- init
方法的下面。
- dealloc
方法的结构应该像这样:
- init
- - (instancetype)init {
- self = [super init]; // 或者调用指定的初始化方法
- if (self) {
- // Custom initialization
- }
- return self;
- }
每当创建
,
- NSString
,
- NSDictionary
,和
- NSArray
类的不可变实例时,都应该使用字面量。要注意
- NSNumber
值不能传给
- nil
和
- NSArray
字面量,这样做会导致崩溃。
- NSDictionary
推荐:
- NSArray * names = @ [@"Marry", @"Maya", @"Vivian", @"Alex", @"Eric", @"Cherry"];
- NSDictionary * products = @ {@"name": @"iPhone 7",
- @"date": @"2016-11-11",
- @"size": @"5.5"
- };
- NSNumber * isHappyToday = @YES;
- NSNumber * phoneNumber = @110120119;
反对:
- NSArray *names = [NSArray arrayWithObjects:@"Marry", @"Maya", @"Vivian", @"Alex", @"Eric", @"Cherry", nil];
- NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"iPhone 7", @"name", @"2016-11-11", @"date", @"5.5", @"size", nil];
- NSNumber *isHappyToday = [NSNumber numberWithBool:YES];
- NSNumber *phoneNumber = [NSNumber numberWithInteger:10018];
当访问一个
的
- 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 里面的所有功能描述,通过 CGRect 隐式数据方法,可以在矩形数据结果计算之前作为输入规范。由于这个原因, 您的应用程序应该避免直接读取和写入 CGRect 中的数据或数据结构。相反, 使用这里描述的函数来操纵矩形和检索他们的特征。
推荐:
- 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;
常量首选内联字符串字面量或数字,因为常量可以轻易重用并且可以快速改变而不需要查找和替换。常量应该声明为
常量而不是
- static
,除非非常明确地要当做宏来使用。
- #define
推荐:
- static NSString * const reusableCellIdentifier = @"Identifier";
- static const CGFloat cellHeight = 50.0;
反对:
- #define reusableCellIdentifier @"Identifier"
- #define cellHeight 20.0
当使用
时,建议使用新的基础类型规范,因为它具有更强的类型检查和代码补全功能。现在 SDK 包含了一个宏来鼓励使用使用新的基础类型 -
- enum
- NS_ENUM()
推荐:
- typedef NS_ENUM(NSInteger, XMButtonsType) {
- XMButtonsTypeAdd,
- XMButtonsTypeDecline
- };
私有属性应该声明在类实现文件的延展(Extension)中。
推荐:
- @interface XMViewController ()
- @property (nonatomic, copy) NSString *privateName;
- @property (nonatomic, assign) NSInteger count;
- @property (nonatomic, strong) NSMutableArray *dataSource;
- @end
图片名称应该被统一命名以保持组织的完整。它们应该被命名为一个说明它们用途的驼峰式字符串,其次是自定义类或属性的无前缀名字(如果有的话),然后进一步说明颜色 和 / 或 展示位置,最后是它们的状态。
推荐:
/
- RefreshBarButtonItem
和
- RefreshBarButtonItem@2x
/
- RefreshBarButtonItemSelected
- RefreshBarButtonItemSelected@2x
图片目录中被用于类似目的的图片应归入各自的组中。
因为
解析为
- nil
,所以没有必要在条件中与它进行比较。永远不要直接和
- NO
进行比较,因为
- YES
被定义为 1,而
- YES
可以多达 8 位。
- BOOL
这使得整个文件有更多的一致性和更大的视觉清晰度。
推荐:
- if (!someObject) {
- }
反对:
- if (someObject == nil) {
- }
对于
来说, 这有两种用法:
- BOOL
- if (isTrue)
- if (![someObject boolValue])
反对:
- if ([someObject boolValue] == NO)
- if (isTrue == YES) // 不要这么做
如果一个
属性名称是一个形容词,属性可以省略 "is" 前缀,但为 get 访问器指定一个惯用的名字,例如:
- BOOL
- @property (assign, getter=isEditable) BOOL editable;
单例对象应该使用线程安全的模式创建共享的实例。(建议使用 GCD 创建单例)
- + (instancetype)sharedInstance {
- static id sharedInstance = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- sharedInstance = [[self alloc] init];
- });
- return sharedInstance;
- }
如果有一个以上的 import 语句,就对这些语句进行分组。每个分组的注释是可选的。
- // Frameworks
- #import <UIKit/UIKit.h>
- // ViewController
- #import "XMViewController.h"
- // Models
- #import "XMUser.h"
- // Views
- #import "XMButton.h"
- #import "XMUserView.h"
为了避免文件杂乱,物理文件应该保持和 Xcode 项目文件同步。Xcode 创建的任何组(group)都必须在文件系统有相应的映射。为了更清晰,代码不仅应该按照类型进行分组,也可以根据功能进行分组。
举例:(按类型分)
来源: