【iOS】サンプルデータ、どうやってアプリに入れますか

# はじめに

Releaseビルドには要らないけど、開発中には使いたいサンプルデータ。このサンプルデータ、どうやってアプリに入れますか?

まず、想定しているサンプルデータの使い方を以下に挙げます。

1. 主にUIの開発に用いる。UIを作るためにも表示するデータがほしい
1. 多言語対応したデータを用意したい。AppStoreのスクショにも使う
    ![screenshot1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73490/322258b1-c6d5-d953-ff60-062b090b9298.png)
1. 開発中は全消しして入れ直すことは多々あるので楽な方法で入れたい
1. テスト用のテストデータのようにパターンを網羅したいわけではない

# どうやって入れますか?

### 1. 手打ちする
入力UIがあるアプリなら都度手打ちして入れるのもありだと思います。少量データならこれで事足りることも。ただ、データ量が多くなるとやはり辛いです。

### 2. ハードコードする
サーバができていない、仕様もFixしていない、主機能の開発に集中したいなどの理由により、少なくとも開発初期段階はこれで進めることが多いと思います。

```swift
// ハードコード!
let user  = User(name: "Taro Yamada",  // 名前
                 country: "Japan",  // 国名
                 age: 30)  // 年齢
```

しかし、開発が進んだ段階では、もう少し何とかしたくなります。ソースコード中にゴミが書かれているのは嫌ですよね?
また、アプリが成長してくると、ビルド時間が長くなってくることがあります。サンプルデータをちょっと修正して再ビルドはストレスに感じるかもしれません。

### 3. フェイクデータ生成ライブラリを使う
ランダムなデータで良ければ、[Fakery](https://github.com/vadymmarkov/Fakery)のようなフェイクデータ生成ライブラリを使うのもありです。ゴミデータがソースコード中に直に書かれているということは避けれますし、実行時にデータが生成されるため、再ビルドの必要もありません。

```swift
// Fakeryの使用例
let faker = Faker()
let user  = User(name: faker.name.name(),  // 名前
                 country: faker.address.country(),  // 国名
                 age: faker.number.randomInt(min: 20, max: 80))  // 年齢
```

### 4. サーバからダウンロードする
Debugビルド時は開発サーバからデータをダウンロードする感じです。サーバを用意したり、ダウンローダーを書いたりとやることが多いですが、Release版に近い形で作れます。サーバ連携するアプリならきっと通る道です。

ただ、作業分担して開発しているとき、自分でサーバを触れるならば良いですが、そうでない場合はサーバ担当者にお願いする必要があり少々面倒です。

あと当たり前ですが、オンラインじゃないと使えません。
経験談ですが、客先でデモするとき、通信環境が必ずしも良好とは限りません。ロードに時間がかかっていると、けっこう気不味い空気になります…。デモ時はオフラインでもサクサク動かせるようにしておきたいですね。

### 5. Mac・iOS間のファイル共有を利用する
Mac PCとiOS端末を直結してアプリにサンプルデータファイルを直接入れます。アプリはファイル読み込みしてデータをよしなに使えるように実装します。

最近、僕はこの方法をよく使うので紹介します。

#### 実装方法

Info.plistに以下のプロパティを追加します。
    
|Key|Type|Value|
|:-:|:-:|:-:|
|Application supports iTunes file sharing|Boolean|YES|

<img width="586" alt="スクリーンショット 2019-12-12 20.21.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73490/5f218082-16db-8da5-c1f3-7a3ff347065d.png">

このプロパティをYESをに設定したアプリは、Mac PCとiOS端末をケーブルで接続すると、FinderからアプリのDocumentsディレクトリが見れるようになります。(macOS 10.15より前はiTunes経由で見れましたが、10.15からはより直感的になりました)

<img width="768" alt="スクリーンショット 2019-12-12 23.20.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73490/7907e407-212c-4277-7910-77aee25bb153.png">

ドラッグ&ドロップでファイルの転送ができるため、あとはアプリ側でDocumentsディレクトリ内の指定ファイルを読み込んでゴニョゴニョすればOKです。なんとでも書けてしまうわけですが、僕はサンプルデータ読込み用のクラスを作っています。ソースコードはこちら↓
https://github.com/HituziANDO/SampleData/blob/master/SampleDataApp/Util/SampleData.swift

このクラスはDocumentsディレクトリ直下に**sampledata**ディレクトリを配置し、その専用ディレクトリ内のファイルを読み込みます。ファイル形式はCodable+JSONDecoderの使い勝手が良いためJSONを扱います。
例えば、以下のようなuser.jsonファイルをsampledataディレクトリ直下に投入します。なお、シミュレータの場合は`~/Library/Developer/CoreSimulator/Devices/{UUID}/data/Containers/Data/Application/{UUID}/Documents/sampledata`ディレクトリ配下にファイルを置いてください。(macOS 10.15.1, Xcode 11.2.1で確認)

```json:user.json
{
  "name": "山田 太郎",
  "country": "日本",
  "age": 30
}
```

Userモデルは以下の通りです。

```swift:User.swift
struct User: Codable {
    var name    = ""
    var country = ""
    var age     = 0
}
```

読み込み方は以下の通りです。ファイル名と型を指定します。他にも重複して読み込まないようにするロックオプションなどがありますが、詳しくはソースコードを読んで頂ければと思います。

```swift
if let user = SampleData.default.import(dataOfFile: "user.json", ofType: User.self) {
    textView.text = """
                    User:
                        name: \(user.name)
                        country: \(user.country)
                        age: \(user.age)
                    """
}
```

もし英語版のサンプルデータを入れたい時はJSONファイルを差し替えてアプリを起動すればOKです。ビルドにサンプルデータを含めているわけではないため、差し替え時に再ビルドの必要はありません。

```json:user.json(英語版)
{
  "name": "Brad Pitt",
  "country": "USA",
  "age": 55
}
```

#### 注意点

Documentsディレクトリがユーザに見える状態になるため、

- Releaseビルド時は`Application supports iTunes file sharing`をNOに設定する
- ユーザに見られたくないファイルはLibraryディレクトリ配下に保存する

などセキュリティホールにならないようにしましょう。

サンプルアプリをGitHubにアップしておきましたので、ご参考にどうぞ。
https://github.com/HituziANDO/SampleData

# まとめ

サンプルデータの入れ方について考察してみました。以下にメリット・デメリットをまとめておきます。

|方法|メリット|デメリット|
|:--|:--|:--|
|手打ち|簡単|・入力頻度、入力データが多いと辛い<br>・そもそも入力UIが必要|
|ハードコード|簡単|・ソースコードが汚くなる<br>・サンプルデータの差し替え時は再ビルドが必要|
|フェイクデータ生成ライブラリ|・サンプルデータの生成が容易<br>・実行時にデータ生成するため、再ビルドが不要|固定データがほしいときは使えない|
|サーバからダウンロード|・サーバ連携するアプリならRelease版に近い形で作れる<br>・サーバ上でサンプルデータの差し替えが可能なため、アプリは再ビルドが不要|・コストが高い<br>・オフラインでは使えない|
|Mac・iOS間のファイル共有|・仕組みを実装した後はお手軽<br>・オフラインでファイルの差し替えが可能なため、再ビルドが不要|Documentsディレクトリがユーザに見える状態になるので注意が必要|