どうも。Reoです。
最近、AppApp を使いたいなーと思うことが増えてきました。
AppApp は、AppStore 上のアプリをコレクションするiOSアプリです。
2年ほど前に審査に通すことができず、リリースを諦め、1年ほど前に GitHub にてコードを公開しました。その時の記事「【iOSアプリ】AppAppのソースコードを公開しました。」にて、リファクタリングブログを書くかもと書いていましたが、すっかりウッカリ気がついたら1年が経ちそうです。
端末には入れてありますが、iOS13になってから AppStore のURLが変わったようで、現状は利用ができない状態になっています。
せっかくなので、ある程度のリファクタリングとiOS13対応をやっていくついでに、記事を書いていこうと思います。
環境
- Xcode 11.3.1
- Swift 5.1.3
- iOS13.3
リポジトリは uruly/AppApp にて公開しています。
今回の目標
今回は、SwiftLint を導入して Warning 潰しをやります。
書き終わってみると、長くなってしまったので、今回は SwiftLint 導入までになりました。導入後にSwift5にアップデートする作業が入ってしまったので...。
ちなみに、1年以上前から更新はしていないはずです。コード公開時にチョットいじったはずですが、実際にリリースを頑張ってた時はもう2年前のことになります。
SwiftLint とは
SwiftLint とは
A tool to enforce Swift style and conventions, loosely based on GitHub's Swift Style Guide.
GitHubのSwift Style Guideに大まかに基づいた、Swiftのスタイルと規則を適用するツールです。
Linter は嫌いな人は多分すんごく嫌いだと思うんですが、コードの品質を保つためには必須なものだと思います。コロンの後にスペース内だけでWarning出してくるので、慣れないうちはすごく鬱陶しいかもしれませんが、慣れます。慣れましょう...。
そもそもライブラリを使うことが苦手だった私は、AppApp の実装当時は存在すら知らなかったかもしれないですね。
仕事で初めて使って、これってデファクトスタンダードなものなのでは?!と感じました。なので、それ以後のプロジェクトには真っ先に導入するようにしています。
個人的に感じているメリットは
- 書き方が統一されて見やすい
- 関数やファイルが長くなることに危機感が持てる
の2点ですね。
さて、SwiftLint が入っていないプロジェクトは一体どれだけこれらができていないのでしょうか。恐ろしいですね。
Mint を使って SwiftLint の導入
さてさて、普段は CocoaPods を使って SwiftLint の導入をしていますが、今回はちょっと Mint ってモノを使ってみようと思います。
realm/SwiftLint の3番目に Using Mint って書かれているヤツですね。
Mint とは
A package manager that installs and runs Swift command line tool packages.
Mint って使ったことないんですよね。
わかってそうな風に書き始めちゃったけど、何も知らないので調べながら書いています。
Swift製コマンドラインツール。以下を読みました。
あとは README をちゃんと読んでみているけれど、うむ、説明できるほど飲み込めないので、とりあえず使ってみますわ。
でも SwiftLint だけを入れるのだったらそんなメリットない?そんなことはない?複数プロジェクトで使うから意味あるかな??(本当によくわかっていない)
Mint の導入は、上記参考記事①をみてやっていきます。
brew install mint
mint version
version: 0.14.1 が入りました。
Mintfileを作成して、1行書いて保存します。
vi Mintfile
// Mintfile内に ユーザ名/リポジトリ名 @ version を記入
realm/SwiftLint@0.39.1
ほいで
mint bootstrap
でMintfileに書いたものをインストールします。
インストール済みのパッケージはスキップされるそうです。これは、別プロジェクトでSwiftLintの同バージョンを使う場合にもスキップされるということで合ってるはず。
mint list
で入っているのを確認できればおkです。
Run Script を書く
Xcodeでプロジェクトを開き、TARGETS > 対象のターゲットを選択 > Build Phases で New Run Script Phases を選択します。
スクリプトを書きます。
if which mint >/dev/null; then
mint run swiftlint swiftlint autocorrect --format
mint run swiftlint swiftlint
else
echo "warning: Mint not installed, download from https://github.com/yonaskolb/Mint"
fi
これであとはルール設定をしたファイルを追加します。
.swiftlint.yml を追加する
.swiftlint.yml を追加します。
その中にルールを書きます。これは、チームや会社でそれぞれありそうだけれど、とりあえず以下のように書きました。
disabled_rules:
- force_cast
included:
- AppApp
excluded:
- Carthage
line_length: 200
large_tuple: 5
file_length:
warning: 500
error: 1200
nesting:
type_level:
warning: 2
identifier_name:
excluded:
- id
- URL
cyclomatic_complexity: 20
included: のところをターゲットに合わせて変更することを忘れないようにしてください。
とりあえずこれで様子を見ます。
ルールについては以下の記事にとても詳しく書かれているので、それぞれのプロジェクトに合わせてルールの設定をしましょう。
公式: https://realm.github.io/SwiftLint/rule-directory.html
SwiftLintの全ルール一覧(Swift 4.2版) - Qiita
disabled_rules でルールを無効にすることができますが、必要最低限にしておいた方がいいはずです。無効にしまくっちゃったらルールをつけている意味とはになってきてしまうので。
これで導入はできました!
いざ。
ビルド........
できねええええええええええええええ!!!!!!
ほぎゃー
先にこれを解決しましょうね。
これは、AppApp をリファクタリングしていくブログであって、SwiftLint 導入することが目的な記事ではないので、どうにかしていきます。
ポチポチするだけではいけない模様
ぐぬぬ...
チョット一旦SwiftLintに死んでもらいます!チョット邪魔!((
Realm のエラーがあってコンバートができないっぽいので手動で直してやります。
'add(_:update:)' is unavailable: Pass .error, .modified or .all rather than a boolean. .error is equivalent to false and .all is equivalent to true.
// 修正前
realm.add(label, update: true)
// 修正後
realm.add(label, update: .all)
Need to upgrade to depend on RealmSwift 3.17 rather than still 3.14 #128より。
修正Doneしたので。
... うーん
Embedded binary is not signed with the same certificate as the parent app. Verify the embedded binary target's code sign settings match the parent app's.
サインインちゃんとしてるはずなんだけど。
困った時のキャッシュ削除をします。
rm -rf ~/Library/Developer/Xcode/DerivedData
rm -rf ~/Library/Caches/com.apple.dt.Xcode
はい、ビルドできました。コンバートもできました。わりと原因不明のビルドできない系は大抵のこれで解決すると思っている...。
改めてSwiftLint導入後を見る...!
さて、先ほどチョット邪魔だったので消した SwiftLint を再度入れて、ビルドをしてみました。
はい...。
Warning は多分全部拾えてないのでまだまだ出てくるはずですね。コロンの後にスペースとかまだまだ出てくるはず。でもさっきSwift5にコンバートした時に少しヨシナニしてくれたみたいで、多少マシになってます。
エラーに出ているほとんどが以下です。
Force Try Violation: Force tries should be avoided. (force_try)
ほぼほぼ try! Realm
なの結構きつくないですか。きついですね。
ちょっとまずいので、一度 .swiftlint.yml の disabled_rules に force_try を追加しました。
disabled_rules:
- force_cast
- force_try
このルールを適用してこんな感じです。
思った100倍くらいマシなんですが、多分追い切れてないだけなはずと思っているので修正始めるのが怖いですね。
実際に修正作業は次回にします!
次回
次は、実際に修正作業を行なっていきます。
Carthage を Mint でほげほげできるらしいんですが、そうすると何がどう良くなるのかまだよくわかってないので、次回の次回くらいに触れたいです。
おわりに
実際に作業をしながら記事を書いているので、グダグダしてしまいますが、そういうシリーズでいこうと思っているのでお許しください。
私は仕事で初めて SwiftLint を使うことになりました。それこそ、仕事をしなかったら一生入れようとは思わなかったかもしれません。
それほど重要なことだとは思っていなかったし、個人だからいいやとも思っていたし、ライブラリを入れるのも苦手だったし、何より存在を知りませんでした。今でも、自分で実装できそうなUI関連のものでライブラリを使うのは苦手です。
なので本当に、お仕事で出会うことができて良かったなぁと思うわけです。
このAppAppリファクタシリーズ(ちゃんと続くよ)は、恐らくほとんどが仕事で得た知識だと思います。
特に許可は得ていません。ただ、1人で始めたアプリ開発がいつしか仕事になって、そうしていつの間にか当たり前になっていることの多くは、1人でやっている時には当たり前ではありませんでした。
そういうことを綴ることで、誰かの何かのきっかけや助けになってくれればなと思います。
というわけで、しばらく続きます!
ではではまた次回。くっそーアイキャッチ画像を作る能力がないぞ。
コメントはありません。
現在コメントフォームは工事中です。