iOS应用开发最佳实践系列一:编写高质量的Objective-C代码
本文由海水的味道编译整理,转载请注明译者和出处,请勿用于商业用途!
点标记语法
属性和幂等方法(多次调用和一次调用返回的结果相同)使用点标记语法访问,其他的情况使用方括号标记语法。
良好的风格:
view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;
不良的风格:
[view setBackgroundColor:[UIColor orangeColor]];
UIApplication.sharedApplication.delegate;
间距
二元运算符和参数之间需要放置一个空格,一元运算符、强制类型转换和参数之间不放置空格。关键字之后圆括号之前需要放置一个空格。
void *ptr = &value + 10 * 3;
NewType a = (NewType)b;
for (int i = 0; i < 10; i++) {
doCoolThings();
}
数组和字典类型的字面值的方括号两边各放置一个空格。
NSArray *theShit = @[ @1, @2, @3 ];
字典字面值的键和冒号之间没有空格,冒号和值之间有一个空格。
NSDictionary *keyedShit = @{ GHDidCreateStyleGuide: @YES };
C函数声明中,左括号的前面不保留空格,并且函数名应该像类一样带有命名空间标识。
良好的风格:
void RNCwesomeFunction(BOOL hasSomeArgs);
长的字面值应被拆分为多行。
良好的风格:
NSArray *theShit = @[
@"Got some long string objects in here.",
[AndSomeModelObjects too],
@"Moar strings."
];
NSDictionary *keyedShit = @{
@"this.key": @"corresponds to this value",
@"otherKey": @"remoteData.payload",
@"some": @"more",
@"JSON": @"keys",
@"and": @"stuff",
};
每一行代码使用4个空格缩进。不使用tab缩进。下图是在Xcode的Preferences进行缩进设置的截图。
方法签名以及其他关键字(if/else/switch/while等)后面跟随的左花括号总是和语句出现于同一行,而右花括号独占一行。
良好的风格:
if (user.isHappy) {
//Do something
}
else {
//Do something else
}
如果一个方法内有多个功能区域,可以使用空行分隔功能区域。
每一行代码不要超过100个字符。
每一个方法之前都有一个99字符宽的注释行,注释行相对于使用空行更能提高代码的辨识度,当一行代码很长的时候,注释行也起到了越界检测的作用。注释行:
///////////////////////////////////////////////////////////////////////////////////////////////////
条件语句
当需要满足一定条件时才执行某项操作时,最左边缘应该是愉快路径代码。不要将愉快路径代码内嵌到if语句中。多个return是正常合理的。
良好的风格做法:
- (void)someMethod {
if (![someOther boolValue]) {
return;
}
//Do something important
}
不良的风格:
- (void)someMethod {
if ([someOther boolValue]) {
//Do something important
}
}
所有的逻辑块必须使用花括号包围,即使条件体只需编写一行代码也必须使用花括号。
良好的风格做法:
if (!error) {
return success;
}
不良的风格:
if (!error)
return success;
或:
if (!error) return success;
三元运算符
长的三元运算符应使用圆括号括起来。三元运算符仅用于赋值和做参数。
Blah *a = (stuff == thing ? foo : bar);
合并的nil三元运算符应该尽量避免。
不良的风格:
Blah *b = thingThatCouldBeNil ?: defaultValue;
多分支条件应该使用if语句或重构为实例变量。
良好的风格:
result = a > b ? x : y;
不良的风格:
result = a > b ? x = c > d ? c : d : y;
异常和错误处理
不要在流控制语句中使用异常(NSException)。
异常仅用于表明程序员的错误。
为了表明一个错误,使用NSError *。
当一个方法通过引用返回一个错误参数,应该检测返回值的状态,而不是错误参数的状态。
良好的风格:
NSError *error;
if (![self trySomethingWithError:&error]) {
// Handle Error
}
不良的风格:
NSError *error;
[self trySomethingWithError:&error];
if (error) {
// Handle Error
}
在方法执行成功的情况下赋值非Null值给错误参数,会使路径跳转到假条件分支(随后程序奔溃)。
代理
除了继承一个类或实现一个协议,否则在头文件中仅使用类声明@class指令,不用#import导入类头文件。
如果一个delegate只有几个方法,比如只是提交和取消,推荐使用block编写动作响应代码。
使用block还是delegate编写回调代码遵循以下几点:(详见参考链接[8])
Ø 如果对象存在多个不同事件,则应该使用代理模式编写各事件的处理代码
Ø 如果对象是单例,应该使用block,而不是代理。
Ø 如果对象是为了其他的信息而进行回调,则使用代理。
Ø 代理更多的是面向于过程,而block则更多的面向于结果。
由于代理方法的声明一般都很长,所以必须将代理对象和其他的协议对象放在实例变量定义的下面,否则实例变量定义的对齐方式将会被打乱掉。
当需要实现多个协议的时候,将每一个协议名拆分到单独的行。
良好的风格:
@interface CustomModelViewController : TTViewController <
TTModelDelegate,
TTURLRequestDelegate
> {
方法
一个方法的命名首先描述返回什么,接着是什么情况下被返回。方法签名中冒号的前面描述传入参数的类型。以下类方法和实例方法命名的格式语法:
[object/class thing+而BOOL类型是8位的unsigned int,即BOOL的值不仅仅是1或0。
良好的风格:
if (!someObject) {
}
不良的风格:
if (someObject == nil) {
}
对于一个BOOL值:两种最佳实践:
if (isAwesome)
if (![someObject boolValue])
不良的风格:
if ([someObject boolValue] == NO)
if (isAwesome == YES) // Never do this.
如果一个BOOL类型的属性名是一个形容词,忽略属性名的“is”前缀是允许的,但需要为访问器指定约定的方法名,比如:
@property (assign, getter=isEditable) BOOL editable;
单例
应该使用线程安全的模式创建共享的单例实例。
+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
Normal
0
10 pt
0
2
false
false
false
EN-US
ZH-CN
X-NONE
$([{£¥·‘“〈《「『【〔〖〝﹙﹛﹝$(.[{£¥
!%),.:;>?]}¢¨°·ˇˉ―‖’”…‰′″›℃∶、。〃〉》」』】〕〗〞︶︺︾﹀﹄﹚﹜﹞!"%'),.:;?]`|}~¢
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:普通表格;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Times New Roman";}
单例的另一种做法,利用+ initialize方法。(JSONModel源码43行:http://t.cn/8F7uBF4):
static JSONAPI*
sharedInstance = nil;
+ (void)initialize {
static dispatch_once_t once;
dispatch_once(&once, ^{
sharedInstance = [[JSONAPI alloc]
init];
});
}
附录
Xcode主题
大部分的开发者都使用Xcode默认的字体颜色主题,其实好的主题不仅能提高源代码的辨识度,同时也增添了编码的乐趣。以下是二款Xcode字体颜色主题链接:
https://github.com/vinhnx/Ciapre-Xcode-theme
https://github.com/tursunovic/xcode-themes
代码片段
熟练使用代码片段库可以提高编码的速度。Xcode4中,打开一个项目并让右侧编辑区可视,然后点击右侧底部面板的第四个{}图标,打开代码片段库,你可以将常用的代码拖入其中。以下是一个最新的开源代码片段库链接:
https://github.com/mattt/Xcode-Snippets
在code snippet library新建如下代码,设定一个类似vci(view controller initialize含义)自动提示快捷键。当开始编写ViewController或View时,键入vci,将相应的代码填入对应的位置。
#pragma mark - init
Method
填入init,initWithFrame等方法
#pragma mark- View
Life Cycle
填入viewdidload,viewdidappear等方法
#pragma mark-
Override Parent Methods
填入updateViewConstraints,updateConstraint, prepareForSegue等方法
#pragma mark-
SubViews Configuration
填入configureSubViews,configureTableView等方法,这里的方法在init方法或view
life cycle被调用
#pragma mark- Actions
填入-(IBAction)action:(id)sender和[self
addtarget:self action:@selector(action:)]动作指向的方法
#pragma mark- Public
Methods
填入在.h外暴露的方法
#pragma mark- Private
Methods
填入.m文件内部调用的方法
#pragma mark-
Delegate,DataSource, Callback Method
填入tableview,scrollview等代理方法
#pragma mark- Getter
Setter
填入对@property初始化的方法
#pragma mark- Helper
Method
填入一些帮助方法,如果使用扩展实现帮助方法不合适,则将帮助方法填在这里
#pragma mark
Temporary Area
填入一些你需要删除,或者不确定后面需不需要用,或者写一写备注之类的,类似代码回收站含义
参考链接
[1] 《NYTimes Objective-C Style Guide》 https://github.com/NYTimes/objective-c-style-guide
[2] 《Coding Guidelines for Cocoa》https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/APIAbbreviations.html
[3] 《iOS-view-frame-builder》https://github.com/rsobik/ios-view-frame-builder/commit/0fa2d81762bc21619b1503d34b7d67160f4678f8
[4] 《Cocoa Style for Objective-C: Part I》 http://cocoadevcentral.com/articles/000082.php
[5] 《Cocoa Style for Objective-C: Part II》http://cocoadevcentral.com/articles/000083.php
[6] 《objective-c-conventionsI》https://github.com/github/objective-c-conventions
[7] 《The official raywenderlich.com Objective-C style guide.》https://github.com/raywenderlich/objective-c-style-guide#cgrect-functions
[8] 《Blocks or Delegation》http://stablekernel.com/blog/blocks-or-delegation/
文档修订历史
时间 |
备注 |
2015-10-18 |
添加code-snippet示例 |
2014-01-16 |
完善代理、条件语句、单例 |
2013-09-07 |
编写高质量的Objective-C代码 |
如果喜欢此文,记得点击文章下方的推荐,以让更多的人有所收获。
文章中如有错误或不当之处望不吝指出,谢谢!
我的邮箱和微博: xdreamarshal@gmail.com, http://weibo.com/xdream86
本文的pdf下载地址。
iOS应用开发最佳实践系列一:编写高质量的Objective-C代码的更多相关文章
- iOS应用开发最佳实践
<iOS应用开发最佳实践> 基本信息 作者: 王浩 出版社:电子工业出版社 ISBN:9787121207679 上架时间:2013-7-22 出版日期:2013 年8月 开本:16 ...
- Web前端开发最佳实践系列文章汇总
Web前端开发最佳实践(1):前端开发概述 Web前端开发最佳实践(2):前端代码重构 Web前端开发最佳实践(3):前端代码和资源的压缩与合并 Web前端开发最佳实践(4):在页面中添加必要的met ...
- iOS应用开发最佳实践:编写高质量的Objective-C代码
本文转载至 http://www.cocoachina.com/industry/20131129/7445.html 点标记语法 属性和幂等方法(多次调用和一次调用返回的结果相同)使用点标记语法访问 ...
- 【Web前端开发最佳实践系列】前端代码推荐和建议
一.常用的前端文件的组织结构: 1.js (放置JavaScript代码) lib(放置框架JavaScript文件) custom.js 2.css(放置CSS样式代码) lib(放置框架CSS文件 ...
- 【WEB前端开发最佳实践系列】CSS篇
一.有效组织CSS代码 规划组织CSS代码:组织CSS代码文件,所有的CSS都可以分为2类,通用类和业务类.代码的组织应该把通用类和业务类的代码放在不同的目录中. 模块内部的另一样式规则:样式声明的顺 ...
- 【WEB前端开发最佳实践系列】JavaScript篇
一.养成良好的编码习惯,提高可维护性 1.避免定义全局变量和函数,解决全局变量而导致的代码“污染”最简单的额方法就是把变量和方法封装在一个变量对象上,使其变成对象的属性: var myCurrentA ...
- 【WEB前端开发最佳实践系列】高可读的HTML
一.HTML语义化 HTML5中增加了很多标签都是基于此类原则设计的(article nav header footer).页面标签语义化的优点是使得搜索引擎以及第三方抓包工具等更容易读懂页面 ...
- 【Web前端开发最佳实践系列】标准的HTML代码
一.验证代码是否符合标准 优点: 标准的页面会保证浏览器正确的渲染 网页能更容易被搜索引擎搜索,提高网站的搜索排名 提高网站的易用性 网页更好维护和扩展 常用工具: W3 Validator HTML ...
- 借助 SublimeLinter 编写高质量的 JavaScript & CSS 代码
SublimeLinter 是前端编码利器——Sublime Text 的一款插件,用于高亮提示用户编写的代码中存在的不规范和错误的写法,支持 JavaScript.CSS.HTML.Java.PHP ...
随机推荐
- 导航 tab
- 谁可以说出HashMap和HashSet的相同点和不同点。
谁可以说出HashMap和HashSet的相同点和不同点. 2011-11-15 20:46ruoshui_t | 浏览 20310 次 Perl 2011-11-15 21:17 #知道行家专业创 ...
- 复习做UWP时涉及到的几种加密签名相关
本人菜鸟一枚,大学里凭兴趣学了一点WP的皮毛,后来又幸运(或者不幸)的进了一家专注于Windows生态的公司做了一段时间的UWP.在博客园写点自己遇到的东西,作为分享,也作为自己的备忘,如果有错误的地 ...
- es2自动发现插件
https://www.elastic.co/guide/en/elasticsearch/plugins/current/discovery-multicast-usage.html http:// ...
- (OAF)jdeveloper集成log4j并将日志输出到指定文件并写入数据库
参考: How to configure Log4j in JDev 11g Ever wanted to use log4j in your adf project ? Well though Or ...
- OAViewObject中clearCache(),reset(),setMaxFetchSize(-1)的使用
今天在页面跳转之后,明明执行了查询,且查询语句正确的情况下,页面不显示数据,且点击SubmitButton包浏览器后退异常. 代码如下: OAViewObjectImpl vo=(OAViewObje ...
- sys.stdin的三种方式
1. for line in sys.stdin: import sys sys.stdout.write('根据两点坐标计算直线斜率k,截距b:\n') for line in sys.stdin: ...
- SQL语句的添加、删除、修改多种方法
SQL语句的添加.删除.修改虽然有如下很多种方法,但在使用过程中还是不够用,不知是否有高手把更多灵活的使用方法贡献出来? 添加.删除.修改使用db.Execute(Sql)命令执行操作╔------- ...
- 【插件开发】—— 1 Eclipse插件开发导盲
[插件开发]—— 1 Eclipse插件开发导盲 在真正接触eclipse插件开发一个月后,对插件的开发过程以及技术要求,也有了一定的了解.遥想之前像无头苍蝇一样乱撞乱学,真心觉得浪费了不少时间. ...
- Linux下OpenSSL的安装与使用
Linux下OpenSSL的安装与使用 OpenSSL简介 OpenSSL是一个SSL协议的开源实现,采用C语言作为开发语言,具备了跨平台的能力,支持Unix/Linux.Windows.Mac OS ...