Swift
Swift3.0

Swift 3.0 Coding Standard

About this Standard

このドキュメントは Swift でのコーディングを効率よく行うために作成したもので、以下の項目を方針としています。

  • プログラマによる記述のブレが少ないこと
  • コードの意図が明確であること
  • 可読性をできるだけ落とさずに、少ない記述量でコーディングできること
  • このドキュメント自体の読みやすさ、把握しやすさが保たれること

なお原則として、Xcode上でエラーになる、または警告が出る書き方については記述しません。

Gratitude

ドキュメントの作成にあたり、複数の他社様規約を参考にさせていただきました。
参考にさせていただいた規約については項番 14. に記載しています。
この場を借りて、お礼申しあげます。


Basic Policy

省略できるものは基本省略する
極端に理解が困難になる場合を除き、記述が少ないことを優先する

1. Naming

1.1. 役割や意図が分かる名前にする

クラス、メソッド、インスタンス変数などは、名前だけで役割や意図が理解できるようにすること
メソッド内変数などスコープが短い変数は、省略した名前を使用してもよい

1.2. キャメルケースで記述する

class、Enum、、定数は大文字で、メソッド、変数、構造体メンバ、caseは小文字で始める

1.3. プレフィックスは書かない

暗黙に名前空間が設定されるので、プレフィックスは書かない

2. Types

2.1. Optional型を使うときは if let / guard let / Nil Coalescing Operator (a ?? b) を使用する

Forced Unwrap は基本的に使わない
初期化時に必ず値が入る IBOutlet などは IUO属性 を使用してよい

if_let
if let unwrap = optional {
    // unwarp を使った処理
} else {
    // アンラップ失敗時の処理
}
guard
guard let selected = tableView.indexPathsForSelectedRows else { return }
// selected を使った処理
Nil_Coalescing_Operator(a??b)
func someMethod(intArray: [Int]?) {
    let value = intArray ?? [Int]()
    // 何らかの処理
}
IUO属性
@IBOutlet weak var someView: UIView! // IBOutlet はデフォルトで IUO属性になる

2.2. ダウンキャストするときは as? を使用する

as! は基本的に使わない
初期化時に必ず値が入り、型が保証されている IBOutlet などは as! を使用してもよい

2.3. Array / Dictionary は= []()で初期化する

var someArray = [String]()

3. Classes

3.1. プロパティ、メソッドへのアクセスは self. を省略する

Xcode の色分けでローカル変数との区別がつくため
コンパイラに指摘されたときは、この限りではない

3.2. サブクラスでは delegate という名前のプロパティは定義しない

親クラスに delegate が定義されている場合に、問題が検出しにくくなってしまうため

3.3. ReadOnly プロパティに get キーワードは記述しない

ReadOnly プロパティには get を書く必要がないため、省略する

class SomeClass: NSObject {
    var base: Float = 10.0
    var twice: Float {
        return base * 2
    }
}

4. Functions

4.1. メソッド名などから類推できる場合はラベルの記述を省略してもよい

アンダースコア(_)を記述することで、呼び出し側はラベルの記述が不要になる

省略する場合
// defenition
public mutating func remove(_ member: Element) -> Element?

// call
allViews.remove(cancelButton)

4.2. internal は省略し、private,public は記述して明示する

public メソッドの override 時、 internal で済むなら、public を書かない

5. Closures

5.1. より短く書ける記法を採用する

Trailing Closures は積極的に使う

// 下記式はそれぞれ等価。より短く書ける記法を採用する
reversed = name.sort({ (s1:String, s2: String) -> Bool in
    return s1 > s2
})

reversed = name.sort({s1, s2 in s1 > s2})  // 暗黙のリターン

reversed = name.sort({ $0 > $1}) // 略式の引数

reversed = name.sort(>)  // オペレータ関数

5.2. クロージャ内で self を参照する場合は弱参照に変える

強参照のままだと循環参照してしまう可能性がある。クロージャの参照元の生存期間が、クロージャよりも明らかに長い場合は、そのまま self を参照して良い。

let aa = UIAlertAction(title: "OK", style: .Default) { [weak self] (_) in // 引数名の省略
    guard let weakSelf = self else { return }
    weakSelf.someAction()
}

5.3. クロージャ内で引数を使用しない場合は _ で省略する

// 5.2. の例参照

6. Control Flow

6.1. guard 節を使う

nil チェックなどで早めにメソッドや制御を抜ける場合は積極的に guard 節を使う

6.2. 単純な条件は()で括らない

if !succeed { return false }

6.3. else は if の閉じ括弧と同じ行に書く

if someFlg {
    // do something
} else {
    // do something else
}

6.4. 複雑にならない程度には三項演算子を使ってよい

return success ? "成功" : "失敗"

7. Threading

7.1. UI更新を伴う処理は main thread で実行する

DispatchQueue.main.async {
 // UI更新処理
}

明らかに main thread で実行されており、処理時間が短い場合はそのまま記述して良い。

8. Enum

8.1. Enum使用時、定義名は省略する

// .alert は UIAlertControllerStyle を省略している
let ac = UIAlertController(title: "タイトル", message: "メッセージ", preferredStyle: .alert)

9. Comments

9.1. ヘッダコメントは省略する

クラスヘッダ / メソッドヘッダは省略し、名前で役割/使い方が理解できることを目指す
どうしても記述したい場合は、行の節約のため、/ * */ ではなく、/// を使う
(参考) Swift 2のドキュメントコメントの書き方(JavaDoc的なやつ)

記述する場合
/// 2倍した値を返す
/// - parameter base: 2倍される値
/// - returns: 2倍した結果
func twice(base: Float) -> Float {
    return base * 2
}

9.2. MARK: は以下のものを使う

MARK: は主に以下のものを使う。1行で記述し、上下に1行空ける。順番は例の通り
// MARK: の後ろにハイフンを書くことで区切り線が入る
delegate 名はAPIファイルの記述をそのまま使用すること推奨
Sub は各人の裁量で増やして良い

// MARK: - Life Cycle
// MARK: - IBAction
// MARK: - XXX Delegate
// MARK: - Public
// MARK: - Protected
// MARK: - Internal
// MARK: - Private
// MARK: - - Sub 1
// MARK: - - Sub 2

9.3. TODO: は使ってよい

改善の余地ありという意味で、残しておいてよい
作業実施は課題と紐づく必要はない。chore でやってもよいし、課題化してもよい

9.4. FIXME: は条件付きで使ってよい

書く場合は、実施する課題の番号とともに書く
作業中に使うのは自由だが、課題番号なしにメインブランチへマージしないこと

10. Formatting

10.1. インデントは 4スペース

10.2. 中括弧はクラス、メソッド、制御文ともに行末に書く

class someClass: NSObject {
    func someMethod() {
        if someFlg {
            // do something
        }
    }
}

10.3. カンマの後はスペースをひとつ空ける

let title = NSLocalizedString("someTitle", comment: "")

10.4. 型指定のコロンは、前はスペースなし、後はスペースひとつ空ける

let someNumber: Int = 10

10.5. 制御文を一行で書く場合、"{"の前後と"}"の前にスペースを一つ空ける

guard let unwrap = optional else { return }

10.6. ファイルの終端は空行を一行挿入する

11. Debug Logs

11.1. デバッグ用ターゲットのみ動作するメソッドを定義して、使用する

例のようなメソッドを定義し、使用する

func dprint(object: Any?, function: StaticString = #function, file: StaticString = #file, line: UInt = #line) {
#if DEBUG
    let format = NSDateFormatter()
    format.dateFormat = "yyyy/MM/dd HH:mm:ss.SSS"
    let encodedFilePath = NSString(string: String(file)).stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.alphanumericCharacterSet())#
    let fileName = NSURL(string: String(encodedFilePath))#.lastPathComponent#
    Swift.print("\(format.stringFromDate(NSDate())) \(fileName) [\(line)] \(function): \(object ?? "nil")", terminator: "\n")
#endif
}

12. File Structures

12.1. protocol や extension は基本的に別ファイルにする

ただし、delegate などそのクラスのみ使用する protocol は同ファイルに記述する
ユーザ定義クラスの extension は同ファイルに記述してもよい

13. Do Not Use

作業中に使うのは自由だが、メインブランチへのマージはしないこと

13.1. assert()

13.2. CGRectMake() / CGSizeMake()

CGRect / CGSize はイニシャライザを使用して生成する

let rect = CGRect(x: 0, y: 0, width: 768, height: 44)
let size = CGSize(width: 768, height: 44)

13.3. マルチバイト文字(日本語や絵文字)のメソッド名

14. References

Swift.org API Design Guidelines(公式)
github/swift-style-guide(和訳)
raywenderlich/swift-style-guide
recruit-lifestyle/swift-style-guide
Swiftでas!と書く場合のガイドライン

変更履歴

Date Modification
2018/3/26 5.2. に補足を追記
7. に Threading を追加。それに伴い以降の項番を修正
2017/2/28 1.2. 定数を小文字始まりから大文字始まりに修正
  • 変更履歴