SwiftLint を導入しました

今さらですが、プロジェクトに SwiftLint を導入しました。
現在のバージョンは 0.16.1 です。

## インストール

Homebrew でも入れましたが、CI のことも考えて [CocoaPods で導入](http://qiita.com/nerd0geek1/items/06c13ef4f95ef4984882)しました。

```Podfile.
  pod 'SwiftLint'
```

Build Phase で + New Run Script Phase して以下のスクリプトを設定します。

```RunScript.sh
"${PODS_ROOT}/SwiftLint/swiftlint"
```

実行の順番は Compile Sources の前にしました。エラーがあればコンパイルの前で止まってくれるので。

## チェック結果

ソースを修正する前にチェックした結果ですが、警告が出なかったもの。

```
  - class_delegate_protocol
  - closing_brace
  - closure_parameter_position
  - comma
  - custom_rules
  - dynamic_inline
  - empty_parameters
  - empty_parentheses_with_trailing_closure
  - function_parameter_count
  - generic_type_name
  - leading_whitespace
  - legacy_cggeometry_functions
  - legacy_nsgeometry_functions
  - mark
  - private_unit_test
  - redundant_string_enum_value
  - redundant_void_return
  - return_arrow_whitespace
  - statement_position
  - unused_enumerated
  - unused_optional_binding
  - valid_docs
  - valid_ibinspectable
  - vertical_parameter_alignment
  - weak_delegate
```

エラーや警告が出たもの。

```
  - colon                               # 変数名などの後ろのコロン (警告 18)
  - compiler_protocol_init              # Set(arrayLiteral: elem) -> [elem] (警告 2)
  - control_statement                   # if や switch などの式に () は不要 (警告 7)
  - cyclomatic_complexity               # 関数の循環的複雑度 (エラー 3, 警告 12)
  - file_length                         # ファイルの行数 (警告 12)
  - force_cast                          # as! (エラー 92)
  - force_try                           # try! (エラー 1)
  - function_body_length                # 関数の行数 (エラー 3, 警告 15)
  - implicit_getter                     # getter だけなら get 不要 (警告 7)
  - large_tuple                         # タプルは2つまで (エラー 1, 警告 1)
  - legacy_constant                     # CGFloat(M_PI) (警告 3)
  - legacy_constructor                  # NSMakeRange (警告 26)
  - line_length                         # 行の長さ (エラー 59, 警告 867)
  - nesting                             # 型のネストが深い (警告 8)
  - opening_brace                       # { の前にはスペース1個 (警告 3)
  - operator_whitespace                 # 演算子を定義する前後にスペース (警告 5)
  - redundant_optional_initialization   # ?付き型の変数を nil で初期化する必要なし (警告 2)
  - shorthand_operator                  # += や -= を使おう (警告 3)
  - syntactic_sugar                     # Dictionary<K, V> -> [K: V] (警告 1)
  - todo                                # TODO 残ってます (警告 2)
  - trailing_comma                      # 配列などの最後の要素の後ろにコロン (警告 95)
  - trailing_newline                    # ファイルの末尾に空行 (警告 2)
  - trailing_semicolon                  # 行末にセミコロン (警告 2)
  - trailing_whitespace                 # 行末にスペース (警告 1718)
  - type_body_length                    # 型の行数 (エラー 4, 警告 9)
  - type_name                           # 型名は3〜40文字 (警告 11)
  - unused_closure_parameter            # クロージャの引数を使わないなら _ に (警告 315)
  - variable_name                       # 型名は3〜40文字 (エラー 121, 警告 39)
  - vertical_whitespace                 # 空行が複数連続 (警告 16)
  - void_return                         # -> () を -> Void に (警告 3)
```

オプトインのもの。

```
  - attributes                          # @obj などのアトリビュートは独立した行に (警告 63)
  - closure_end_indentation             # クロージャの最後の } のインデント (警告 72)
  - closure_spacing                     # なし
  - conditional_returns_on_newline      # なし
  - empty_count                         # .count == 0 -> .isEmpty (エラー 10)
  - explicit_init                       # なし
  - file_header                         # ファイルの先頭のコメントの書式 (警告 52)
  - first_where                         # .filter {...}.first -> .first {...} (警告 9)
  - force_unwrapping                    # ! 使うな (警告 49)
  - missing_docs                        # public にはドキュメント (警告 2)
  - nimble_operator                     # なし
  - number_separator                    # 3桁ごとに _ (警告 40)
  - object_literal                      # UIImage(named: ...) をどうしろと？ (警告 100)
  - operator_usage_whitespace           # 演算子を使用する前後にスペース (警告 6)
  - overridden_super_call               # メソッドを override したら super を呼ぶ (なし)
  - private_outlet                      # @IBOutlet は private にすべし (警告 44)
  - prohibited_super_call               # なし
  - redundant_nil_coalescing            # なし
  - sorted_imports                      # import をアルファベット順に (警告 31)
  - switch_case_on_newline              # なし
```

## 設定

チェック結果を踏まえて、とりあえず以下の設定としましたが、随時見直す予定です。

```.swiftlint.yml
# MyAppフォルダのソースのみを対象とする。
included:
  - MyApp

# 無効にするルール。
disabled_rules:
  - cyclomatic_complexity
  - file_length
  - force_cast
  - force_try
  - function_body_length
  - legacy_constant
  - legacy_constructor
  - large_tuple
  - line_length
  - nesting
  - operator_whitespace
  - redundant_optional_initialization
  - todo
  - trailing_comma
  - type_body_length
  - type_name
  - unused_closure_parameter
  - variable_name
  - vertical_whitespace

# デフォルト無効のルールのうち、有効にするもの。
opt_in_rules:
  - closure_spacing
  - conditional_returns_on_newline
  - explicit_init
  - nimble_operator
  - operator_usage_whitespace
  - overridden_super_call
  - prohibited_super_call
  - redundant_nil_coalescing
  - switch_case_on_newline

# 空行のスペースを許容する。
trailing_whitespace:
  ignores_empty_lines: true
```

空行のスペースについては、最初は以下の custom_rules でやろうと思いましたが、[SwiftLint の Issues](https://github.com/realm/SwiftLint/issues) を検索して[この pull request](https://github.com/realm/SwiftLint/pull/616) で ignores_empty_lines を知りました。
(ちなみに、custom_rules の regex は [.dotMatchesLineSeparators が有効](https://github.com/realm/SwiftLint/blob/master/Source/SwiftLintFramework/Extensions/File%2BSwiftLint.swift#L17)になっているので、改行にマッチしたくない場合は . の代わりに [^\n] を使う必要があります。)

```.swiftlint.yml
disabled_rules:
  - trailing_whitespace

custom_rules:
  trailing_whitespace_in_non_empty_line:
    regex: "[^ \t\n][ \t]+$"
```

各ルールの設定については、swiftlint rules の結果にも書いてありました。

```console
$ swiftlint rules
+-----------------------------------------+--------+-------------+------------------------+-----------------------------------------------------------------------------------------------------+
| identifier                              | opt-in | correctable | enabled in your config | configuration                                                                                       |
+-----------------------------------------+--------+-------------+------------------------+-----------------------------------------------------------------------------------------------------+
...
| trailing_whitespace                     | no     | yes         | yes                    | warning, ignores_empty_lines: false, ignores_comments: true                                         |
...
+-----------------------------------------+--------+-------------+------------------------+-----------------------------------------------------------------------------------------------------+
```

(select * from rules where opt-in = no とかできればいいのに…。)