刚刚在线

分享iOS开发技术经验的自媒体网站

禅与Objective-C编程艺术(译)

禅与 Objective-C 编程艺术 (Zen and the Art of the Objective-C Craftsmanship 中文翻译)

原文 https://github.com/objc-zen/objc-zen-book

前言

我们在 2013 年 11 月份开始写这本书,最初的目标是提供一份如何编写干净漂亮的 Objective-C 代码的指南:现在虽然有很多指南,但是它们都是有一些问题的。我们不想介绍一些死板的规定,我们想提供一个在开发者们之间写更一致的代码的途径。随时间的推移,这本书开始转向介绍如何设计和构建优秀的代码。

这本书的观点是代码不仅是可以编译的,同时应该是 “有效” 的。好的代码有一些特性:简明,自我解释,优秀的组织,良好的文档,良好的命名,优秀的设计以及可以被久经考验。 本书的一个理念是是代码的清晰性优先于性能,同时阐述为什么应该这么做。 虽然所有的代码都是 Objective-C 写的,但是一些主题是通用的,并且独立于编程语言。

Swift

在 2014 年 6 月 6 日,苹果发布了面向 iOS 和 Mac 开发的新语言: Swift。 这个新语言与 Objective-C 截然不同。所以,我们改变了写这本书的计划。我们决定发布这本书当前的状态,而不是继续书写我们原来计划写下去的主题。 Objective-C 没有消失,但是现在用一个慢慢失去关注的语言来继续写这本书并不是一个明智的选择。

贡献给社区

我们将这本书免费发布并且贡献给社区,因为我们希望提供给读者一些有价值的内容。如果你能学到至少一条最佳实践,我们的目的就达到了。

我们已经非常用心地打磨了这些文字,但是仍然可能有一些拼写或者其他错误。我们非常希望读者给我们一个反馈或者建议,以来改善本书。所以如果有什么问题的话,请联系我们。我们非常欢迎各种 pull-request。

作者

Luca Bernardi

Alberto De Bortoli

关于中文翻译

译者

林翔宇 - http://linxiangyu.org - linxiangyu@nupter.org - http://github.com/oa414

庞博 - bopang@sohu-inc.com - https://github.com/heistings

翻译已得到原作者许可,并且会在更加完善后申请合并到原文仓库。

部分译文表达可能存在不妥之处,非常欢迎各种修订建议和校队。 请直接 fork 本仓库,在 README.md 文件中修改,并申请 pull request 到 https://github.com/oa414/objc-zen-book-cn/

条件语句

为了避免错误,条件语句体应该总是被大括号包围,即使可以不这样做(比如,条件语句体只有一行内容)。可能的错误是:多加了第二行,并且误以为它是 if 语句体里面的。此外,更危险的是,如果把 if 语句体里的一行注释掉了,之后的一行代码会成为 if 语句里的代码。

推荐:

1
2
3
if (!error) {
    return success;
}

不推荐:

1
2
if (!error)
    return success;

或者

1
if (!error) return success;

在 2014年2月 苹果的 SSL/TLS 实现里面发现了知名的 goto fail 错误。

代码在这里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
                                 uint8_t *signature, UInt16 signatureLen)
{
  OSStatus        err;
  ...

  if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
    goto fail;
  if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
    goto fail;
    goto fail;
  if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
    goto fail;
  ...

fail:
  SSLFreeBuffer(&signedHashes);
  SSLFreeBuffer(&hashCtx);
  return err;
}

显而易见,这里有没有括号包围的2行连续的 goto fail; 。我们当然不希望写出上面的代码导致错误。

此外,在其他条件语句里面也应该按照这种风格统一,这样更便于检查。

尤达表达式

不要使用尤达表达式。尤达表达式是指,拿一个常量去和变量比较而不是拿变量去和常量比较。它就像是在表达 “蓝色是不是天空的颜色” 或者 “高个是不是这个男人的属性” 而不是 “天空是不是蓝的” 或者 “这个男人是不是高个子的”

Yoda

(译者注:名字起源于星球大战中尤达大师的讲话方式,总是用倒装的语序)

推荐:

1
if ([myValue isEqual:@42]) { ...

不推荐:

1
if ([@42 isEqual:myValue]) { ...

nil 和 BOOL 检查

类似于 Yoda 表达式,nil 检查的方式也是存在争议的。一些 notous 库像这样检查对象是否为 nil:

1
if (nil == myValue) { ...

或许有人会提出这是错的,因为在 nil 作为一个常量的情况下,这样做就像 Yoda 表达式了。 但是一些程序员这么做的原因是为了避免调试的困难,看下面的代码:

1
if (myValue == nil) { ...

如果程序员敲错成这样:

1
if (myValue = nil) { ...

这是合法的语句,但是即使你是一个丰富经验的程序员,即使盯着眼睛瞧上好多遍也很难调试出错误。但是如果把 nil 放在左边,因为它不能被赋值,所以就不会发生这样的错误。 如果程序员这样做,他/她就可以轻松检查出可能的原因,比一遍遍检查敲下的代码要好很多。

为了避免这些奇怪的问题,可以用感叹号来作为运算符。因为 nil 是 解释到 NO,所以没必要在条件语句里面把它和其他值比较。同时,不要直接把它和 YES 比较,因为 YES 的定义是 1, 而 BOOL 是 8 bit的,实际上是 char 类型。

推荐:

1
2
3
if (someObject) { ...
if (![someObject boolValue]) { ...
if (!someObject) { ...

不推荐:

1
2
3
if (someObject == YES) { ... // Wrong
if (myRawValue == YES) { ... // Never do this.
if ([someObject boolValue] == NO) { ...

同时这样也能提高一致性,以及提升可读性。

原文 https://github.com/objc-zen/objc-zen-book