AppApp のリファクタリングを始めます!【SwiftLint 導入編】

どうも。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.

https://github.com/realm/SwiftLint

 

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.

https://github.com/yonaskolb/Mint

Mint って使ったことないんですよね。

わかってそうな風に書き始めちゃったけど、何も知らないので調べながら書いています。

Swift製コマンドラインツール。以下を読みました。

  1. Swift製コマンドラインツールのパッケージ管理ツール「Mint」のセットアップ&操作方法
  2. Swift 製の Mac ターミナルプログラムを Mint インストール対応しましょう!

あとは 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人でやっている時には当たり前ではありませんでした。

そういうことを綴ることで、誰かの何かのきっかけや助けになってくれればなと思います。

 

というわけで、しばらく続きます!

ではではまた次回。くっそーアイキャッチ画像を作る能力がないぞ。

 

AppApp ,

Comments...

コメントは認証制です。詳しくは下記の注意をお読みください。お気軽にコメントお願いします!

Write a Comment

コメント時の注意

「Twitter」「Facebook」「Google+」「WordPress」のいずれかのアカウントをお持ちの方は各アカウントと連携することでコメントできます。 コメントしたことはSNSに流れませんので、アカウントをお持ちの方はこちらの方法でコメントを投稿して下さると嬉しいです。 アカウントをお持ちでない方はメールアドレスで投稿することができます。 初回コメント時は承認後に表示されます。

Related Memo...

UITableView.RowAnimation の .none はアニメーションするよ

UITableView.RowAnimation の .none はアニメーションがnoneなわけじゃなく、デフォルトの設定を使うよという意味らしい。

The inserted or deleted rows use the default animations.

なのでアニメーションしちゃう。今更の気づき。

 

iOS

UINavigationController + UIScrollView の組み合わせで使っている時に謎の余白ができる時

UINavigationController + UIScrollView の組み合わせで使っていて、UIScrollView 上に AutoLayout で上下左右0で View を設置しているのに、30px程度上にずれてしまうとき。

`navigationController.navigationBar.isTranslucent = false` にすると直るかもしれない。

ScrollView上のコンテンツとNavigationBarの重なっているところが透過していたら多分これで直せるはず。

通常のターゲットではちゃんと動いているのに、iOSSnapshotTestCase を用いたテストでだけこの対応が必要なのよくわからないけれど。。。

iOS

記事を書くほどでもないけれどメモっておきたいこと

テスト投稿。

例えばiphone7 の画面サイズ

750 × 1334
半分375 × 667

iOS
more