开发规范

前⾔

本⽂文档编写的⽬目的在于确⽴立⼀一系列列切实可⾏行行的准则,应⽤用于iOS项⽬目开发⼯工作中,以提⾼高开发效率及 代码质量量,使得项⽬目代码更更易易于维护、拓拓展。

提⾼高项⽬目可维护性是本⽂文档贯彻始终的基本原则。

  • 为读者准备:良好的开发规范下产⽣生的代码,将有利利于开发⼈人员阅读与理理解,进⽽而能⾼高效地编改代码,形成良性循环。对于⼀一个有历史的项⽬目,阅读代码花费的时间将不不可忽视,往往⽐比编写代码需要更更⻓长的时间。

  • 保持⼀一致:尽可能与开发平台⻛风格⼀一致,这样有利利于提⾼高⾃自我的开发⽔水平,更更好地理理解苹果开发团队的设计思想。⼀一致的代码⻛风格,利利于实现更更好的⾃自动化,如更更有效地开发和操作格式化或重构代码的⼯工具。

  • 代码即⽂文档:⻛风格⼀一致且规范的代码,本身就是详尽的⽂文档,另写⽂文档在⼤大多数情况下都是不不必要且没有⼤大帮助的。当然,适当的注释还是很有价值的。本⽂文档会有少量量介绍,解释规范制定的理理由,但不不是Object-C教程,如不不熟悉Object-C语⾔言,可阅 读苹果公司的《Programming with Objective-C》。同时,本⽂文档主要参考⾃自苹果公司的Coding Guidelines for Cocoa,Google公司的Google Objective-C Style Guide。

约定

基于不不同的准则其效⽤用及影响不不尽相同,所以本⽂文档中的开发规范将划分为不不同级别。 • 【必须】:必须遵守的规范,违反将引起严重后果。 • 【严格】:严格遵守的规范,违反可能引起不不良后果,没有特殊情况不不应违反。 • 【建议】:建议遵守的规范,遵守规范将有利利于项⽬目的管理理、稳定及安全,提⾼高⼯工作效率。

范例例

以下是摘⾃自Gogle开发团队的范例例,其中已展示了了基本的代码规范,

#import

@class Bar;

/**

** A sample class demonstrating good Objective-C style. All interfaces,*

** categories, and protocols (read: all non-trivial top-level declarations*

** in a header) MUST be commented. Comments must also be adjacent to the*

** object they're documenting.*

*/

@interface Foo : NSObject

/* The retained Bar. /

@property(nonatomic) Bar *****bar;

/* The current drawing attributes. /

@property(nonatomic, copy) NSDictionary<NSString *****, NSNumber ***> ***attributes;

/**

** Convenience creation method.*

** See -initWithBar: for details about @c bar.*

** @param bar The string for fooing.*

** @return An instance of Foo.*

*/

+ (instancetype)fooWithBar:(Bar *****)bar;

/**

** Initializes and returns a Foo object using the provided Bar instance.*

** @param bar A string that represents a thing that does a thing.*

*/

- (instancetype)initWithBar:(Bar *****)bar NS_DESIGNATED_INITIALIZER;

/**

*** Does some work with @c blah.

** @param blah*

** @return YES if the work was completed; NO otherwise.*

*/

- (BOOL)doWorkWithBlah:(NSString *****)blah;

@end

#import "Shared/Util/Foo.h"

@implementation Foo {

/* The string used for displaying "hi". /

NSString *****_string;

}

+ (instancetype)fooWithBar:(Bar *****)bar {

return [[self alloc] initWithBar:bar];

}

- (instancetype)init {

// Classes with a custom designated initializer should always

override

// the superclass's designated initializer.

return [self initWithBar:nil];

}

- (instancetype)initWithBar:(Bar *****)bar {

self = [super init];

if (self) {

_bar = [bar copy];

_string = [[NSString alloc] initWithFormat:@"hi %d", 3];

_attributes = @{

@"color" : [UIColor blueColor],

@"hidden" : @NO

};

}

return self;

}

}

- (BOOL)doWorkWithBlah:(NSString *****)blah {

// Work should be done here.

return NO;

}

@end

命名规范

基本原则

• Clarity:清晰,在合理理的范围内,名称应尽可能具有描述性。 • Consistency:⼀一致,相同含义的属性、变量量、⽅方法命名应尽可能保持⼀一致,即使在不不同的类中。

如:NSArray与NSDictionary的属性count。 • No Self Reference:不不要⾃自我指涉,简单地说就是不不要使⽤用⾃自身类型名作后缀。如:ABCString

(规范的),ABCStringObject(不不规范,⾃自指涉)。 ⼀一般命名规范

适⽤用但不不限于变量量、常量量、属性、参数、⽅方法、函数、宏等。

【必须】命名有明确的含义,且具有⼀一定的描述性,不不能使⽤用汉语拼⾳音(多⾳音字不不利利于理理解,易易引 起歧义),不不能使⽤用⽆无意义或过于简单的命名。

【必须】命名准确清晰。不不能因命名过⻓长⽽而采取缩略略的⽅方式(如:setBackgroundColor:,缩略略成 setBgColor:),不不使⽤用⽣生僻、易易⽣生歧义的词汇。

【必须】禁⽌止⾃自我指涉,除掩码或通知常量量外,如:NSUnderlineByWordMask, NSTableViewColumnDidMoveNotification。

【必须】驼峰命名⽅方式。采⽤用⼩小写字⺟母开头的驼峰命名⽅方式。C函数的名称和typedef采⽤用⼤大写字⺟母 开头的驼峰命名⽅方式。

【必须】不不能以保留留字或关键字名命,如:id。

【严格】命名应该具有上下⽂文甚⾄至全局⼀一致性,如具备相同含义或者作⽤用,命名⽅方式应该相同或者 类似。

前缀

【必须】类,协议,全局函数和全局常数通常应以前缀开头,以避免在全局名称空间中命名冲突, 前缀以⼤大写字⺟母开头。

【严格】前缀应使⽤用与项⽬目代号相同的缩写,因苹果保留留使⽤用两个字⺟母的前缀,所以前缀应不不少于 三个字⺟母,以避免命名冲突。

【严格】前缀不不应出现在⽅方法命名中(⽅方法具有与类相同的命名空间),不不应在结构体各个field中 使⽤用前缀。

缩写

【必须】不不使⽤用⾮非标准的缩写(包括词组、句句⼦子⾸首字⺟母缩写),除约定俗成的缩略略词(C语⾔言流传⾄至 今的alloc、dealloc等)、计算机通⽤用名词缩写(如:ASCII,PDF,XML,HTML,URL,RTF, HTTP,HTTPS,TIFF,JPG,PNG,GIF,LZW,ROM,RGB,CMYK,MIDI,FTP等)外。

image

类别(Category)

【必须】对外开放使⽤用的类别,类别名称应以“扩展的类名+“+”+项⽬目前缀+扩展的功能简述”格式命 名,如:NSString+ABCParsing。

【必须】对外开放使⽤用的类别,其公开⽅方法名称应以“项⽬目前缀_⽅方法名称”格式命名,防⽌止在全局命 名空间中冲突,如:abc_length。

【建议】不不对外开放的类别,其命名可不不带有项⽬目前缀。 ⽅方法

【必须】⽅方法名称以⼩小写字⺟母开头,尽可能以单句句的⽅方式命名(各个参数串串起来如句句⼦子⼀一般), 如:- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view

【必须】因苹果开发团队会在⽅方法前加下划线“ _ ”,为避免⽅方法覆盖,禁⽌止在⽅方法前⾯面加下划线。

【必须】如类继承⾃自⼀一个Cocoa framework的⼤大型类,类内的私有⽅方法以“项⽬目前缀_⽅方法名称”格式 命名,避免与⽗父类私有⽅方法名冲突,引起异常问题。

【必须】类的实例例初始化⽅方法必须带“init”前缀。如类的私有⽆无返回值⽅方法是为了了初始化⼀一个引⽤用类 的实例例,⽅方法应带上“setUp”、“create”等相关语义前缀,但不不能使⽤用“init”。

【必须】⽅方法参数前必须有关键字以表明参数的意义。

如: - (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view; - (CGPoint)convertPoint:(CGPoint)point :(UIView *)view;

【必须】返回对象的⽅方法应具有以名词开头的名称,⽤用于标识返回的对象,

如: - (Bread *)bread;//Good.

//Good. //Bad.

  • (Bread *)makesBread;//Bad

【严格】参照苹果的准则,获取单⼀一返回值的⽅方法不不应以get开头,间接或获取多个返回值的⽅方法可 以get开头。

如:- (BOOL)getWhite:(nullable CGFloat *)white alpha:(nullable CGFloat *)alpha。 Accessor⽅方法(setter & getter)

【必须】Accessor⽅方法应以属性名称命名,不不应以get开头。 如:- (id)delegate;⽽而⾮非- (id)getDelegate;

【严格】根据属性命名的含义,选择合适的前缀(is,enable,can、should、will等),但其属性命 名或其是⼀一个动词则不不需要。

如: @property(nonatomic, getter=isEditable) BOOL editable; @property(nonatomic) BOOL showsMask; - (BOOL)isEditable;

【严格】点表示法只适⽤用于属性,不不适⽤用于⽅方法。 如: BOOL isGood = self.glorious;

BOOL isGood = [self isGlorious]; BOOL isGood = self.isGlorious;

函数

【必须】⾮非静态函数应以“项⽬目前缀+函数名”格式命名。因为Objective-C不不提供命名空间,所以⾮非静 态函数应具有前缀,以最⼤大程度地减少名称冲突的可能性,函数名遵循驼峰格式。

【建议】静态函数可不不带项⽬目前缀,但静态函数遵循⾮非静态函数命名规范会更更好。 集合类⽅方法

【必须】处理理array、dictionary、set等集合类⽅方法,命名中应包含元素对象类型的提示。常⽤用格式 有“add+Element”,“remove+Element”,“elements”等等。

如: - (void)addChildViewController:(UIViewController *)viewController; - (void)removeChildViewController:(UIViewController *)viewController;

  • (NSArray *)childViewControllers;

【严格】当有返回值,且是集合类型时,如果是有序或已排序的数据集合,应返回不不可变数组,否 则应返回⽆无序集合类型(如:NSSet,NSDictionary等)。

【严格】当有返回值,且是集合类型时,如集合内元素类型是确定的,应标示元素类型,以便便在编 译阶段得到有效提示。

如: - (NSArray *)childViewControllers; 代理理⽅方法

【严格】代理理⽅方法命名应以消息发送者标识作为⽅方法前缀,第⼀一个参数(即触发delegate⽅方法调⽤用 的消息发送者对象)紧跟其后,除⾮非只有⼀一个参数。

如: - (void)tableView:(UITableView *)tableView shouldSelectRow:(int)row; - (void)application:(NSApplication *)sender openFile:(NSString *)fileName; - (void)browserDidScroll:(Browser *)sender; - (void)windowShouldClose:(UIWindow *)sender;

协议⽅方法

【严格】如是⼀一个与特定类相关的协议,应以“相关类名+Delegate/Protocol”格式命名。如: UITableViewDelegate。

【建议】如是⼀一个通⽤用的协议,不不与特定类相关,命名以动词形式为好。如:NSLocking⽐比NSLock 更更好。

参数

【必须】⽅方法参数命名以⼩小写字⺟母开头,具有⼀一定的描述性,能直接或间接提示参数的类型和含 义。不不要使⽤用⽆无意义、缩略略或过于简单的词汇命名。

如: - (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view; - (CGPoint)convertPoint:(CGPoint)p fromView:(UIView *)v;

  • (CGPoint)convertPoint:(CGPoint)one fromView:(UIView *)two;

【必须】⽅方法参数命名不不要添加“pointer”或”ptr”来表示参数是否为指针。

【严格】当参数是集合类型,且集合内元素类型是确定的,应标示元素类型,以便便在编译阶段得到 有效提示。

如: - (void)addSubviews:(NSArray *)subviews;

常量

【必须】枚举常量量⽤用于定义⼀一组相关且单独使⽤用的整型值,应以typedef NS_ENUM⽅方式定义,名称 需带有项⽬目前缀,各常量量应以“枚举名+值描述”格式命名。

如: typedef NS_ENUM (NSInteger, ABCLayoutMode) { ABCLayoutModeHorizontal = 1,

ABCLayoutModeVertical = 2 }

【必须】位掩码常量量⽤用于定义⼀一组相关且可组合使⽤用的位值(整型),应以typedef NS_OPTIONS ⽅方式定义,名称需带有项⽬目前缀,各常量量应以“掩码名+值描述”格式命名。

如: typedef NS_OPTIONS (NSInteger, ABCLayoutMask) { ABCLayoutMaskHeight = 1 << 0,

ABCLayoutMaskWidth = 1 << 1, }

【建议】对于位掩码常量量,加上空组合与全组合的定义,甚⾄至是⼀一些常⽤用组合定义,这样会显得⽐比 较完整,且有利利于使⽤用时简化代码。

如: typedef NS_OPTIONS (NSInteger, ABCLayoutMask) {

ABCLayoutMaskNone = 0,

ABCLayoutMaskHeight= 1 << 0,

ABCLayoutMaskWidth= 1 << 1,

ABCLayoutMaskAll = 0x0003

}

【必须】全局常量量以const的⽅方式定义,静态常量量以static const⽅方式定义,不不能以宏⽅方式定义常量量。 宏只是在使⽤用的地⽅方直接展开,没有类型也不不做任何类型检查,⼤大量量使⽤用宏会导致⼆二进制⽂文件变 ⼤大,编译速度下降。

【必须】全局常量量命名以项⽬目前缀开头,⾸首字⺟母⼤大写驼峰格式,以extern的⽅方式公开共享。

如: extern const CGFloat ABCWindowHeight = 300; extern NSString * const ABCWindowTitle = @“ABC”;

【必须】静态常量量命名以⼩小写字⺟母k开头,⾸首字⺟母⼤大写驼峰格式。 如: static const int kLocalFileMaxCount = 12;

static NSString * const kLocalFilePrefix = @“ABC”;

Notification与Exception常量量

【必须】Notification常量量⼀一般就是字符串串常量量,以“发送者+Did|Should|Will+通知描述 +Notification”格式命名(“发送者”应有项⽬目前缀),这是⼀一个允许⾃自我指涉的例例外。

如: NSApplicationDidBecomeActiveNotification; UIKeyboardWillChangeFrameNotification。

【必须】Exception常量量⼀一般就是字符串串常量量,以“触发者+异常描述+Notification”格式命名(“触发 者”应有项⽬目前缀),这是⼀一个允许⾃自我指涉的例例外。

如: NSColorListIOException;

【严格】宏名称采⽤用全⼤大写格式,单词间以下划线“_”连接。

编码规范

类⽅方法

+(void)load的使⽤用 此⽅方法在类被加载(引⽤用)时由系统⾃自动调⽤用,且只执⾏行行⼀一次,其调⽤用时机要早于main⽅法。 此⽅方法不不遵循继承规则,⼦子类如没有实现则不不会调⽤用⽗父类,⽗父类与⼦子类如都有实现将分别调⽤用,⽗父类的load⽅方法会先于⼦子类调⽤用。 此⽅方法在category中实现不不会覆盖原类的load⽅方法,都会被执⾏行行且原类先执⾏行行;如多个

category都实现load⽅方法,则都会被执⾏行行,执⾏行行顺序同category编译顺序。

【必须】在load⽅方法中不不能执⾏行行任何实例例⽅方法,不不能初始化任何⾮非系统类实例例(⼀一般情况下,系统 类会先于⾃自定义类加载),不不能调⽤用任何⾮非系统类的类⽅方法。

【必须】在load⽅方法中不不能执⾏行行耗时操作,避免影响App启动。

【必须】此⽅方法是由系统⾃自动调⽤用,不不能显式调⽤用。

【严格】没有必要,不不要实现load⽅方法。如需实现⽅方法交换,则只能交换当前类的⽅方法。

类⽅方法+ (void)initialize的使⽤

此⽅方法在类对象第⼀一次收到消息时被调⽤用,因此会先于其他⽅方法(load⽅方法除外)执⾏行行,且 只执⾏行行⼀一次。同时,此⽅方法的调⽤用遵循继承规则,即使没有通过[super initialize]⽅方式调⽤用,⽗父类此 ⽅方法依然会被调⽤用。

当⼦子类有实现此⽅方法时,会覆盖⽗父类initialize⽅方法。

当⼦子类没有实现此⽅方法时,⽗父类initialize⽅方法可能会被多次调⽤用。 当收到消息进⾏行行初始化 时,其中⼀一般都会调⽤用⽗父类初始化⽅方法,进⽽而会向⽗父类发送消息,触发⽗父类初始化操作。当类对象 进⾏行行初始化操作时,会⾃自动调⽤用initialize⽅方法。由于⼦子类没有实现initialize⽅方法,系统会沿继承链查 找,这会导致⽗父类initialize⽅方法被调⽤用多于⼀一次。

【必须】此⽅方法是由系统⾃自动调⽤用,不不能显式调⽤用,需要触发可使⽤用⽆无害的调⽤用⽅方式, 如: [ABCModel self];

【严格】当需要在此⽅方法执⾏行行初始化代码,当前类应实现此⽅方法避免⽗父类initialize被多次调⽤用。 【严格】此⽅方法内的代码如只应执⾏行行⼀一次,应在dispatch_once()内执⾏行行,预防被多次调⽤用。

实例例初始化

iOS内有Designated Initializer和Secondary Initializer(convenience)的概念。即指定初始化 ⽅方法和次要(便便利利)初始化⽅方法。⼀一般地,苹果会以NS_DESIGNATED_INITIALIZER标志指定初始 化⽅方法。为简化描述,以下“指定⽅方法”指代“指定初始化⽅方法”,便便利利⽅方法指代“次要(便便利利)初始化 ⽅方法”。

⼀一个类中,指定⽅方法和便便利利⽅方法可以有多个,指定⽅方法主要作⽤用是完成必要的初始化⼯工作, 便便利利⽅方法主要为调⽤用者提供简易易的调⽤用⽅方式。⼀一般地,指定⽅方法所需参数要⽐比便便利利⽅方法完备(个数 较多),当然这不不是必然的,需因应情况⽽而定。

【必须】⼀一个类中的指定⽅方法必须调⽤用⽗父类的指定⽅方法,不不能调⽤用⾃自身的指定⽅方法,不不能调⽤用⾃自身 的便便利利⽅方法,不不能调⽤用⽗父类的便便利利⽅方法。

image

【必须】当有多个指定⽅方法和便便利利⽅方法时,应在指定⽅方法定义中以NS_DESIGNATED_INITIALIZER 明确告知调⽤用者,同时有助于编译器器分析,及早发现问题。

【必须】便便利利⽅方法之间只能单向调⽤用,且必须有⼀一个调⽤用了了⾃自身的指定⽅方法,不不能调⽤用⽗父类的指定 ⽅方法。

【必须】便便利利⽅方法如已调⽤用了了⾃自身的指定⽅方法,则不不能再调⽤用其他便便利利⽅方法。

【必须】如⽗父类的指定⽅方法不不适于当前需求,或⼦子类不不允许使⽤用,须override⽗父类指定⽅方法,并在 Debug环境下通过断⾔言(NSAssert)给出警告。

【必须】任何初始化⽅方法都不不应调⽤用accessor⽅方法,继承和多态等技术的应⽤用,在⽗父类的实现中可 能调⽤用了了accessor,导致调⽤用到⼦子类重写的accessor,⽽而此时⼦子类部分并未完全初始化或已经销 毁,从⽽而出现⼀一系列列的逻辑问题甚⾄至崩溃。

【必须】不不要在初始化⽅方法中调⽤用公开的⽅方法,避免⼦子类override引起异常。

【严格】不不要实现memory zone的相关⽅方法,苹果保留留相关API但实际上已弃⽤用。

【严格】不不要使⽤用new来获取实例例对象,不不要实现new⽅方法。new只使⽤用默认的⽅方法(init)初始 化;alloc-init⽅方式将有更更好的使⽤用灵活性(alloc分配内存,init初始化)。

【建议】初始化⽅方法中如有⼤大量量初始化⼯工作,可考虑提供公开⽅方法由调⽤用者决定调⽤用时机。

实例例销毁(dealloc)

在ARC下,dealloc⽅方法在对象释放时由系统⾃自动调⽤用,如有必要可在其中处理理⼀一些事务,如 释放资源、反注册监听、记录事件等。

【必须】不不能显式调⽤用dealloc⽅方法,不不能使⽤用[super dealloc]。

【必须】不不能在其中调⽤用accessor⽅方法,原因参照实例例初始化。

【严格】不不能在其中调⽤用的⽅方法中把self作为参数传递出去,除⾮非能保证self在⽅方法调⽤用返回后不不会 被retain,否则将有可能引起多次释放导致崩溃。

【建议】dealloc⽅方法应置于@implementation下,指定⽅方法之上,如没有需要不不需要实现。

Block

在iOS中,block是以对象的形式存在的,其使⽤用场景多是⼀一对⼀一的调⽤用,可以是同步也可以 是异步执⾏行行。

block使⽤用需要注意循环引⽤用的问题,前提是block的所有者被block捕获持有,或block⼀一直 不不释放。没有引⽤用外部变量量是全局block;引⽤用了了外部变量量但block没有赋值给其他变量量(ARC下会 ⾃自动copy到堆,即使没有调⽤用copy)则是栈blokc(系统在其⽣生命周期结束时⾃自动回收释放),因 此栈和全局block都不不存在循环引⽤用的问题。

block使⽤用前需要判空,否则会引起崩溃,其主要原因是调⽤用block时,实际是尝试通过内部

函数指针执⾏行行⽅方法,由于block为空其地址是0x0,得不不到正确指针值⽽而导致崩溃(此时会报引起崩

溃的address=0x10,0x10 = 16)。 struct __block_impl {

void *isa;//8字节 int Flags; //4字节 int Reserved;//4字节 void *FuncPtr; //8字节

}

【必须】当block内有引⽤用到block的持有者,应使⽤用weak⽅方式传递,避免引⽤用循环,除⾮非能确保这 是⼀一个栈block。 【必须】使⽤用block前必须判空。

Notification

通知是观察者模式的⼀一个实现,主要应⽤用的场景是⼀一对多的状态通知,当有多个监听者时, 以串串⾏行行的⽅方式通知,执⾏行行线程与post消息所在线程相同。post消息的对象应是⼀一个公共组件(服 务),消息内容应是其所处状态的表达。

【必须】通知是备选项,不不是⾸首选项,即在没有合适的⽅方式实现时,才考虑使⽤用通知。

【必须】⼀一对⼀一交互(回调)场景,禁⽌止使⽤用通知⽅方式实现。

【必须】处理理通知的⽅方法如涉及到UI相关操作,应确保在主线程执⾏行行。

【必须】post通知时,当需要通过notification传递更更多信息,应使⽤用userInfo参数传递。

【必须】通知处理理⽅方法不不应有耗时操作,如有则须使⽤用notificationQueue进⾏行行异步发送通知,或在 ⼦子线程执⾏行行耗时操作,避免线程阻塞。

Delegate

代理理模式适⽤用于⼀一对⼀一交互,通过协议定义⼀一系列列相关⽅方法调⽤用。多步骤、流程化、可定制 业务⽐比较适合使⽤用代理理模式,如:UITableViewDelegate。

【必须】必须弱引⽤用delegate,只能⽤用weak,不不能使⽤用assign或strong,避免循环引⽤用或崩溃。 【建议】当⼀一对⼀一的回调较多时,可考虑使⽤用代理理模式替代block⽅方式回调。

持久化

【严格】不不要使⽤用UserDefaults存储⼤大量量数据,其synchronize⽅方法会阻塞当前线程,数据量量⼤大应使 ⽤用⽂文件或数据库。 【严格】⼤大量量数据更更新到数据库,应以事务⽅方式写⼊入,提⾼高安全性和速度。

【严格】避免频繁读写数据库,常⽤用数据读取后应以适当⽅方式缓存。

集合对象

常⽤用的集合对象有NSSet,NSArray,NSDictionary,NSCache,NSHashTable, NSMapTable等。

【必须】不不能使⽤用空的对象初始化集合对象,必须判空,避免crash。

【必须】不不能把空对象添加到集合对象,必须判空,避免crash。

【必须】在多线程环境下,对可变集合对象进⾏行行增删操作时,应使⽤用合适的加锁保护。

【必须】在多线程环境下,不不能传递可变集合对象(参数或返回值)。

【必须】在多线程环境下,不不能直接遍历可变集合对象,应通过copy得到不不可变集合对象再进⾏行行遍 历,或使⽤用合适的加锁保护。

【严格】缓存数据尽量量使⽤用NSCache替代NSMutableDictionary。

【建议】集合对象尽量量使⽤用泛型定义,明确其中元素的类型。

如:NSArray() *textArray; 懒加载

懒加载是延迟对象初始化,在需要时才加载。其适⽤用场景如下: • ⼀一个对象是否创建依赖于其他对象的使⽤用情况。 • ⼀一个对象在运⾏行行过程中不不⼀一定被使⽤用,或不不⼀一定需要存在。 • ⼀一个对象的创建会消耗⼤大量量系统资源和性能。

【必须】不不符合懒加载应⽤用场景,不不要使⽤用懒加载,特别是在继承的情况下。

【必须】如使⽤用懒加载的对象在使⽤用过程中,有可能被置nil,则不不应使⽤用懒加载。

【严格】懒加载的⽅方法⾥里里应只有初始化对象的相关代码,不不应包含业务逻辑。

多线程

对于多线程,当 前应⽤用较多的是GCD

(Grand Central Dispatch )。GCD通过 层级式设计,利利⽤用线程 池管理理各种线程队列列。 主线程与线程池则是相 互独⽴立的。

【必须】禁⽌止使⽤用dispatch_get_current_queue()获取当前线程队列列信息。如有需要,应使⽤用 dispatch_queue_set_specific对队列列设置标识,然后使⽤用dispatch_get_specific获取标识进⾏行行判断。

【必须】使⽤用默认优先级队列列,不不能随意设置线程队列列优先级,当多条具有不不同优先级线程访问共 享资源时,将极容易易引发阻塞或死锁。

【必须】UI相关操作必须在主线程上执⾏行行。

【必须】不不能在主线程执⾏行行耗时操作,尽可能在⼦子线程处理理。

【必须】在⼦子线程处理理数据I/O,进⾏行行⽂文件读写。

【必须】不不能在主线程发起同步⽹网络请求,⽹网络请求及其数据处理理应在⼦子线程执⾏行行。

【严格】只有必须保证执⾏行行顺序时才使⽤用同步⽅方法(dispatch_sync,等待任务完成后返回),否则 应使⽤用异步⽅方法(dispatch_async,不不等待)添加任务。

【严格】不不要在Runloop没有正确运⾏行行的线程上执⾏行行performSelector⽅方法。

内存管理理

【必须】在⽅方法或函数返回前,正确释放其中使⽤用到的CoreFundation对象。

【严格】慎重使⽤用__bridge_retained和__bridge_transfer,这会涉及到对象所有权的转移。

【严格】慎⽤用单例例模式,减少不不必要的内存占⽤用。单例例模式只适⽤用于对象是全局唯⼀一,App⽣生命周 期内皆需要使⽤用且会被多个不不同类型对象引⽤用,具有普适功能,存储公共资源数据。

【严格】单例例初始化⽅方法内不不能进⾏行行其他单例例调⽤用。

【严格】不不要使⽤用NSArray/NSDictionary/NSSet存储UI相关对象,如有需要,应使⽤用NSHashTable (类同NSMutableArray)或NSMapTable(类同NSMutableDictionary)。

类的设计

【严格】合理理使⽤用继承,⽗父类应整合稳定且公共的变量量与⽅方法,⼦子类应只具备⽗父类没有的特性和功 能。 【严格】⽗父类不不要override公共属性的accessor⽅方法,如有必要,应定义成公共⽅方法。

【建议】优先考虑组合模式,减少继承。如需要扩展类功能,优先考虑以category或protocol实现。

【建议】不不要在头⽂文件定义成员变量量,属性尽量量定义为只读。

【建议】头⽂文件应只定义公开⽅方法、只读属性、必要的类引⽤用。

其他

【必须】使⽤用KVO必须保证addObserver与removeObserver配对使⽤用。

【必须】以SDK形式提供给外部使⽤用的,所有接⼝口⽅方法都应有简明易易懂的注释,必要时加上例例⼦子说 明其作⽤用及注意事项。

【严格】提供给外部使⽤用的⽅方法、函数、属性等,都应有简明易易懂的注释。

【严格】⾮非简易易,或调⽤用频繁的代码⽚片段,不不要以宏⽅方式定义,应以函数⽅方式取代宏。

【严格】所有条件语句句后的代码都应以{}包裹,避免歧义。

【严格】switch语句句分⽀支末尾应有break,避免fall through。

【严格】在⽅方法或函数中会重复使⽤用(⾮非赋值)且通过⽅方法调⽤用获取的对象(数值),应以变量量保 存对其引⽤用。 【严格】少⽤用⽆无符号数,除⾮非与系统API对接,或有明确的理理由和⽤用途。

【严格】⽅方法应遵循单⼀一职责原则,⼀一个⽅方法应只实现⼀一个具体的功能,确保⽅方法的输⼊入与输出可 预期且稳定。如有多个步骤,应把每个步骤拆分成⼀一个⽅方法调⽤用。

【严格】有可能产⽣生异常的代码,应以@try-@catch-@finally⽅方式处理理,如⾮非必要不不应使⽤用throw来 抛出异常。同时注意收集信息,以备后查。

【严格】不不要把整型值、浮点值、指针值、位运算结果作为布尔值返回,但可返回逻辑运算结果。

【建议】不不要与YES直接⽐比较,BOOL的值可能不不仅是预期的1(YES)或0(NO)。

【建议】如⾮非必要,不不要公开可变对象类型的属性。

【建议】公开⽅方法的参数,公开的属性,应以nonnull或nullable标示其是否可为空。

【建议】对于⽀支持NSCopying协议的类,在声明属性时使⽤用copy⽐比strong要好。如:NSString。

【建议】对于对象(实例例,类)⽅方法调⽤用,检查对象是否为空是不不必要的。

【建议】有效代码⾏行行数不不要超过80⾏行行(滚动不不超过两屏),如超出,可考虑拆分为多个⽅方法。

【建议】如⾮非必要,不不要在⽅方法中添加注释。

【建议】业务或功能上相关的数据模型,应尽可能精简,提取共性部分,合理理使⽤用继承,减少数据 模型之间互相转换。

【建议】在元素多变的cell上慎⽤用约束,当数据量量较⼤大时,约束会消耗⼤大量量的计算性能。

Git

【必须】拉取或提交代码前,应先执⾏行行fetch,拉取最新提交信息,检查是否存在问题,避免潜在的 回滚⻛风险。

【必须】拉取提交信息后,如有更更新节点,执⾏行行rebase拉取新代码并⽣生成新节点(不不能使⽤用 merge),如有冲突,在本地处理理好冲突后,再执⾏行行push。

【必须】分⽀支合并时,必须先通过merge与⽬目标分⽀支同步,如有冲突,在本地处理理好冲突后,再执⾏行行 merge把合并节点同步到⽬目标分⽀支上。

【必须】在本地完成合并后,必须先运⾏行行验证,重点查看有冲突的相关功能是否与预期相符。在验 证通过后,才能推送节点到服务器器。

【必须】提交信息格式:“[feature/bug]简易易描述”。

【必须】主分⽀支(master)版本发布,不不要在master分⽀支上提交未经测试的代码。

【必须】开发分⽀支(develop)集成测试、回归测试、联调开发,不不要在develop提交与当前开发版 本⽆无关的代码。通过测试后⽅方可合并到master。

【必须】功能分⽀支(feature)需求开发与模块测试,根据需求建feature分⽀支,通过功能测试后⽅方可 合并到develop。

【必须】功能分⽀支以“版本号+feature-需求/功能名称”格式命名,路路径为“origin/feature/”。

【严格】当迭代两个版本后,旧的功能分⽀支应及时删除。

你可能感兴趣的:(开发规范)