タイマーアプリをリファクタリングする

# はじめに

iPhoneアプリ開発集中講座にあるタイマーアプリのリファクタリングに挑戦してみたいと思います。

> 楽器アプリの「Day 1 Lesson 4-4 ステップアップ リファクタリングで見通しを改善しよう」(P.165) で学びましたね。タイマーアプリが完成してからでかまいませんので、楽器アプリで学んだことを思い出して、コードの冗長性をなくしてみてください。
> (iPhoneアプリ開発集中講座 P.257より引用)

# リファリングとは

Twitterのツイートを引用しますが、ソフトウェア開発の上で読みづらくなったコードを整理して可読性の向上と勘違いによる不具合発生の防止が主な目的となると思います。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">好きな文章を引用<br><br>&gt; ソフトウェアの開発は、繰りかえしに次ぐ繰り返しです。読みづらくなるまでコードを書き足し、そのコードをリファクタリングする、その繰り返しです。そして、より簡潔なコードを書くために、本書が少しでもお役に立てばと思います。</p>&mdash; アユム@1月からWebエンジニア (@ex_endeavor) <a href="https://twitter.com/ex_endeavor/status/1274686457714597888?ref_src=twsrc%5Etfw">June 21, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 実際に考えてみる

## まずどんな構造にするのか？

タイマアプリは、下記のような用件があると思います

1. タイマーカウントダウン
2. タイマーのカウントダウンする設定値を読み出し
3. タイマーのカウントダウンする設定値の書き込み
4. UIの表示

４つほどあると思います。

そこでファイルを分けることを考えます。下記のように分けてみました。

| 用件                                         | ファイル                                              | メモ                                               |
| -------------------------------------------- | ----------------------------------------------------- | -------------------------------------------------- |
| タイマーカウントダウン                       | CountDownManager.swift(新規)                          | タイマーのカウントダウンを検討する                 |
| タイマーのカウントダウンする設定値を読み出し | SettingManager.swift(新規)                            | UserDefaultsの読み出しを行う                       |
| タイマーのカウントダウンする設定値の書き込み | SettingManager.swift(新規)                            | UserDefaultsの読み出しと、取りうる値を管理する |
| UIの表示                                     | ViewController.swift<br />SettingViewController.swift | 従来のファイルのままとする                         |

<img width="693" alt="スクリーンショット 2020-06-30 15.11.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42735/39a32aa5-b2a7-2279-6a57-30960d0ac44d.png">


これから紹介するコードはこちらのgithubに公開しますので参考にしてください。

- [[github]MyTimer2019](https://github.com/FromF/MyTimer2019)

## タイマーカウントダウン

タイマーカウントダウンするTimerManager.swiftを作りました。

課題となるのは、１秒毎にタイムアウトしたときにViewController.swiftにどのように通知するか？です。そこで今回はdelegateを用いてUI表示更新してみることにしました。

下記のようにdelegateメソッドを定義しています。

```swift
protocol TimerManagerDelegate: class {
    func timerInterrupt(remainCount:Int)
}
```

また、いくつかのメソッドを定義しました。

| メソッド名 | 概要                                         |
| ---------- | -------------------------------------------- |
| start      | タイマーカウントダウンを開始する             |
| stop       | タイマーカウントダウンを停止する             |
| clear      | タイマーの設定値などを変わった時にクリアする |

また、外部公開する変数（プロパティー）を１つ定義しました。

| 変数名     | 概要               |
| ---------- | ------------------ |
| timerValue | タイマーの設定時間 |



## 設定値を管理する

設定値を管理するSettingManager.swiftを作りました。

UIPickerViewで表示する設定の選択肢のリストと、タイマーの設定値の取得と設定する変数（プロパティー）を定義しました。

| 変数名        | 概要                                                         |
| ------------- | ------------------------------------------------------------ |
| setttingArray | UIPickerViewで表示する設定の選択肢のリスト                   |
| timerVaue     | タイマーの設定時間<br />UserDefaultsから値を取得、設定する<br />設定するときは、TimerManager.swiftに設定値を更新して、クリアをする |



## 起動

アプリが起動する時にタイマーカウントダウンするTimerManager.swiftのtimerValueを初期化する処理を追加しました。

```swift
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        // タイマーマネージャーのインスタンス取得
        let timerManager = TimerManager.shared
        // 設定マネージャーのインスタンス取得
        let settingManager = SettingManager.shared
        // 設定マネージャーで保持している設定時間をタイマーマネージャーに渡す
        timerManager.timerValue = settingManager.timerVaue
        return true
    }
```



# 終わりに

様々なリファクタリングがあると思います。

まずは一例として捉えていただければと思います。ありがとうございました。