2017年4月15日土曜日

凛としてSwift (血闘編ノ壱)

割と凹みやすいアルマイトな性格です。

いくつかの軽い(Swift成分の低い)プロジェクトにSwiftLintを導入してみて、なんとなく把握できたので、次はSwift率の高いプロジェクトにSwiftLintを導入してみることにしました。

予想通り、数え切れないワーニングとエラーが吐かれますね。ため息が出ますね。当然これをちくちくと直していかなければならないのですが、先頭からひとつひとつやっていると、最後にたどり着く前にメンタルがやられそうです。

そこでXcodeの問題ナビゲーターからいったん目をそらして、個々の対処法について考えてみます。
  1. 素直に修正する。
  2. 特定の箇所だけLintの例外にする。
  3. ymlファイルを編集して、Lintのルールを緩める。
  4. 放置する。
  5. SwiftLintの導入を断念する。
まず5.は避けたいですね。せっかくなんだし。何より、現行のソースがLint適用済みになれば、その後はソースを修正する都度Lintが指摘してくれるわけですから、辛いのは最初だけです。

次に4.は「ダメ、絶対!」ですね。これから先ソースを修正していくのに、修正しなければならないエラーやワーニングが、Lintのワーニングに埋もれてしまってはバグの温床になります。

そうなると1.2.3になりますが、できるだけ1.で頑張って、ちゃんとした理由がある時にかぎって2.、それでもしょうがないときは3.ということにします。

そうしよう、そうしよう。

で、そらしていた目をワーニングの山に向けます。先頭から順にやっていくのも芸がないですよね。それに全て修正し終わってからgitのコミットをしていたのでは粒度が大きくなるので、うっかりエンバグしていたときに、追いかけるのが大変になりそうです。そこで少しだけ工夫をします。

ymlファイルを編集して、エラー/ワーニングの元になっているルールを一時的に全てdisabledにします。そしてエラー/ワーニングがなくなった状態から、disabledにしたルールをひとつずつ有効にして、同じワーニング毎に潰していきます。これなら修正対象は全て同じ種類になるので、作業が楽になります。上記1,2,3の判断もしやすくなりますし、さらにコミットの粒度も下がります。

ymlファイルを抜粋すると、こんな感じですか。

これで、エラー/ワーニングが出力されなくなったので、機械的に修正できる簡単なものから手をつけていきます。

opening_braceを、disabled_rulesから削除すると、こういったところが指摘されます。

えー、Paul Hegarty先生だってこう書いてたぢゃん。 Objective-Cの流れでこうなんじゃないのー、って愚痴りながら修正します。


この他にもこういうところにワーニングが出ますね。

If文の条件にカッコが必要ないことなど、スッキリした文法になっている分、各語句の前後や、{ } の前後の空白はきちんと入れましょうということですね。


「凛としてSwift (血闘編ノ弐)」につづく。


こんな風に手を入れているチューナーアプリです。よろしくね。


♪♪♪


こちらもどうぞ。
凛としてSwift
凛としてSwift (血闘編ノ弐)
凛としてSwift (血闘編ノ参)
帰ってきた凛としてSwift(くるくる編)


2017年3月15日水曜日

凛としてSwift

“Swiftize”という謎単語を思いつきました。

僕の作っているiOS用アプリは大部分がObjective-Cで書かれています。もちろん新たに追加する部分はSwiftで書いているので、全体の2, 3割がSwiftで書かれているでしょうか。それでSwiftのバージョンが上がるたびに派手にエラー・警告が吐かれるという罰ゲームを受けています。

仕様変更しすぎでは。。。

そんなことからObjective-Cで書かれた処理をあえてSwiftで書き直すのは、まだ時期尚早なのでは、と手をつけていませんでした。でも、ひとつのプロジェクトでSwiftとObjective-Cが混ざった状態というのは、著しく生産性が落ちるのです。頭がパッパと切り替わらないのです。おっさんなのです。

今から思えば、中途半端に混ぜるようなことはしないで、一気に書き換えるようにすれば良かったなぁ。

でもSwiftもバージョン3になりましたしね、ここは一念発起して少しづつ"Swiftize"していこうと決めました。

そこで、どうせなら綺麗なソースを書きたいので、SwiftLintを導入することにしました。

SwiftLint本体はHome Brewでインストールしました。
$ brew install swiftlint
==> Downloading https://homebrew.bintray.com/bottles/swiftlint-0.16.1.sierra.bottle.tar.gz
######################################################################## 100.0%
==> Pouring swiftlint-0.16.1.sierra.bottle.tar.gz
🍺  /usr/local/Cellar/swiftlint/0.16.1: 37 files, 13.6M
$ swiftlint version
0.16.1
$ 

次に、Xcodeのプロジェクトを開いて、TARGETS > Build Phases で、Run Script Phaseを追加します。

1. TARGETSを選択します。


2. Build Phasesで”+”をクリックします。


3. New Run Script Phaseを選びます。


4. Run Scriptが追加されるので、開きます。



5. Swift LintのREADME.mdにある、シェルスクリプトをコピペします。
if which swiftlint >/dev/null; then
  swiftlint
else
  echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi

6. プロジェクトのディレクトリに、.swiftlint.ymlを追加してLintのルールをカスタマイズします。
$ cd HelloSwiftLint/
$ ls -la
total 8
drwxr-xr-x  7   foobar  staff   238  2  3 04:02 .
drwxr-xr-x  8   foobar  staff   272  2 17 00:09 ..
-rw-r--r--  1   foobar  staff  1465  2  3 04:02 .swiftlint.yml     ←これを追加します
drwxr-xr-x  7   foobar  staff   238  2  2 03:03 HelloSwiftLint
drwxr-xr-x  5   foobar  staff   170  2  2 02:42 HelloSwiftLint.xcodeproj
drwxr-xr-x  4   foobar  staff   136  2  2 02:49 HelloSwiftLintTests
drwxr-xr-x  4   foobar  staff   136  2  2 02:49 HelloSwiftLintUITests
$
.swiftlint.ymlの中身は、やはりREADME.mdをお手本にして修正を加えます。
最低限設定するべき箇所は、included:とexcluded:です。
included:にはチェックするソースへのPATHを指定します。
これはプロジェクトの直下にある、プロジェクトと同名のディレクトリを指定すればいいと思います。(これを指定しないとプロジェクトの下全部が対象になるのかな? そんな感じがするんだけど)
excluded:には逆にチェックしたくないファイルへのPATHを指定します。
CocoaPodsを使用しているならPodsとか。あと、include:で指定した下に、何か外部のライブラリを置いたような時、それを除外するよう指定できます。

ルールのカスタマイズとは言っても、特別なことはしていません。ただ、デフォルトではかなり厳しいチェックが行われますので、ルールを少し緩めています。

disabled_rules:には、チェックしない項目を指定します。
ここには1行の長さをチェックしないように追加しました。ご存知のように、AppleのAPIはのけぞる長さですからね。

type_body_length:は1個の型の定義(クラスとかね)の行数、file_length:は1ファイルの行数です。
これは適当に大きめに変更します。ただ、ソースにルールを合わせたのでは、本末転倒になりますからほどほどに。

type_name:は型名(クラスとか)の長さ、variable_name:は変数名の長さです。
型名はともかく、変数名は1文字から使いたいのでmin_length:は指定なしにしてあります。


あ、 gitを使っているなら、.gitignoreに.swiftlint.ymlを追加しておくのもいいですよ。
(省略)
#Swift Lint
.swiftlint.yml
( 省略)


6. .swiftlint.ymlができたら、 プロジェクトを開いてビルドします。
警告が、だばぁ〜

7. ワーニングが山ほど出ますので、涙をこらえながら、ひとつひとつ修正していきます。

ちょっと気になったのは、警告対象の箇所を修正しても、警告を示す黄色の表示が消えないことがあったことです。開いているのとは別のファイルに警告が残っているときに、その警告が開いているファイルに表示されるということが、しばしば起こるようです。

修正したのに警告表示が消えないなぁ、というような時は一旦そのファイルを閉じて、Xcodeの左の問題ナビゲーターに表示されているワーニングメッセージをダブルクリックして、その警告が指しているSwiftファイルを開きなおすと、うまく問題の箇所に黄色の表示が現れると思います。

※2017/05/16追記
この不具合はSwiftLintをバージョン0.18.1に更新したら起きなくなりました。どうやら修正されたようです。


正直、Lintが指摘する書き方に対して、「えー、そこはこう書くだろぉ〜、普通ぅ〜」というようなことは、ままありますが、そんなもん慣れです。その書き方に慣れてさえしまえば、ちょっとした書き違い(間違いじゃなくて)がなくなって、可読性がよくなります。こういうことの積み重ねがバグの少ないプログラムに繋がっていくんだろうな、って思ってます。

、、、たぶんね(白目)。

しかしSwift、もう少しコンパイルが早くなりませんかね?「凛としてSwift (血闘編ノ壱)」に続きます。


♪♪♪


こちらもどうぞ。
凛としてSwift (血闘編ノ壱)
凛としてSwift (血闘編ノ弐)
凛としてSwift (血闘編ノ参)
帰ってきた凛としてSwift(くるくる編)