R.Swiftのプラグインの導入方法（Xcode project編）

2022/11/29に R.Swift 7.0.0 がリリースされ、Swift Package Manager ビルドツールプラグインの機能が追加されました。この R.Swift プラグインの導入方法についてREADMEに沿って説明します。

- R.Swift 7.0.0 リリースノート
    - https://github.com/mac-cain13/R.swift/releases/tag/7.0.0
- リリース一覧
    - https://github.com/mac-cain13/R.swift/releases

:::note info
インフォメーション
記事執筆現在、既に 7.2.4 がリリースされており、引き続き頻繁なリリースが続きそうな勢いです。
導入される方は最新のリリースを導入すると良いと思います :ok_woman: 
:::

# R.Swiftのプラグインとは

R.Swiftにはこれまでプラグインの機能はありませんでした。今回の7.0.0で新規に追加されたものです。
この機能により、R.generated.swiftが自動生成されます。

なお、そもそもプラグインとは何かを知りたい方は、以下の記事を読まれることをおすすめします :pray: :sparkles: 

https://qiita.com/usamik26/items/1c2cec0903fea2e03344


# R.Swiftのプラグインの導入方法

R.Swiftのプラグインの導入方法は、２種類あります。

- Xcode project
    - Xcode project の "Package Dependencies" から R.Swift を追加する方法
- Package.swift
    - Package.swift に記述する方法

当記事では、Xcode project で導入する方法を説明します。

[README.md](https://github.com/mac-cain13/R.swift#xcode-project---spm) をみると以下のように丁寧に説明されています。
結論から言えば、この通りにやればもう完璧なのですが、私は最後かなり戸惑ったのでその実体験をもとに、スクショと共に一緒に見ていきたいと思います :muscle: 

> ### Xcode project - SPM
> 
> 1. In Project Settings, on the tab "Package Dependencies", click "+" and add `github.com/mac-cain13/R.swift`
> 2. Select your target, on the tab "General", in the section "Frameworks, Libraries, and Embeded Content", click "+" and add `RswiftLibrary`
> 3. Select your target, on the tab "Build Phases", in the section "Run Build Tool Plug-ins", click "+" and add `RswiftGenerateInternalResources`
> 4. Right-click on your project, click `RswiftModifyXcodePackages`, click `Run`, click `Allow Command to Change Files`
> 5. Build your project, now the `R` struct should be available in your code, use auto-complete to explore all static references

## 1. In Project Settings, on the tab "Package Dependencies", click "+" and add `github.com/mac-cain13/R.swift`

SwiftPMを使っている方にはおなじみのとこです。

プロジェクト設定の "Package Dependencies" タブを開き、"+"　ボタンをクリックします。
![1-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/c676ec98-602f-3781-c776-85c4615fa860.png)

右上の検索バーに `github.com/mac-cain13/R.swift` を入力し、R.Swiftを検索します。
"Dependency Rule" を適宜変更してください（画像の場合は、 `Up to Next Major Version` で、7.0.0以上を指定しています）。
![1-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/7c4e9114-6b2d-6ac6-a490-1052d5e1598a.png)

"Package Product" で選択候補が2つ出ますが、 `RswiftLibrary` のみチェックを入れます。

:::note warn
戸惑った点
コマンドラインツールの `rswift` はチェックしなくてもOKでした。
:::

![1-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/a068552b-da68-a74f-04a6-203617c73317.png)

パッケージ追加後の様子
![1-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/0434ca88-c1b4-227a-88a0-fe28b90479dc.png)

## 2. Select your target, on the tab "General", in the section "Frameworks, Libraries, and Embeded Content", click "+" and add `RswiftLibrary`

ターゲット設定を選択し、"General" タブを開き、"Frameworks, Libraries, and Embeded Content" のセクションで、 "+" をクリックします。
![2-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/aca1d718-5b17-e941-7ca6-38e83bf84c2f.png)

検索バーに `RswiftLibrary` を入力し、表示されている `RswiftLibrary`を選択して、追加ボタンをクリックします。
![2-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/35568500-fd5e-e09d-d2b7-1bd1f2a76891.png)

`RswiftLibrary` 追加後の様子
![2-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/cacf08e5-176c-9371-bb56-4d5f209a7889.png)

## 3. Select your target, on the tab "Build Phases", in the section "Run Build Tool Plug-ins", click "+" and add `RswiftGenerateInternalResources`

ターゲット設定を選択し、"Build Phases" タブの "Run Build Tool Plug-ins" セクションで、"+" をクリックします。
![3-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/49c41852-706f-14b4-bbe8-7fa537b787eb.png)

検索バーに `RswiftGenerateInternalResources` を入力し、表示されている `RswiftGenerateInternalResources`を選択して、追加ボタンをクリックします。
![3-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/cd515688-0eac-09ec-f970-728d0a8b7562.png)

ビルドツールプラグイン追加後の様子
![3-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/d8afa05f-d820-5209-21a5-aa7cfda3946a.png)

## 4. Right-click on your project, click `RswiftModifyXcodePackages`, click `Run`, click `Allow Command to Change Files`

プロジェクト上で右クリックし、`RswiftModifyXcodePackages`をクリックします。
![4-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/02122cca-58c8-741b-8339-a251a748cd7f.png)

`Run` をクリックします。
![4-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/063ef469-3046-1d63-f25e-45682bb27828.png)

その後ダイアログが出てきたら、 `Allow Command to Change Files` をクリックします。

## 5. Build your project, now the `R` struct should be available in your code, use auto-complete to explore all static references

プロジェクトをビルドします。

...これで `R` 構造体がコードで利用可能になりました！
え？とここで戸惑った点は以下の通りです。

:::note warn
戸惑った点
`R.generated.swift` ファイルを、手動で生成する必要はありません。
:::

:::note warn
戸惑った点
`import Rswift` を書く必要はありません。
:::


# `R` 構造体の使用方法

Swiftファイルで、 `R.` と入力すると、オートコンプリートですべての静的リファレンスを検索できます。

この項では、以下の使用例を記述します。

| 対象 | 事前準備 | 例 |
|:-:|:-:|:-:|
| 文字列  | Localizable.strings を追加し、文字列を追加しておく | `"greeting" = "Hello, world!";` という文字列を追加 |
| 画像  | Assets に Image Set を追加しておく  | `icon` という名前の Image Set を追加 <img width="600" alt="画像" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/26a9ca1e-fd8c-f3e5-fdb1-60638582589b.png"> |
| 色  | Assets に Color Set を追加しておく  | `primary` という名前の Color Set を追加 <img width="600" alt="色" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/753e7dfa-3bc3-46bb-1538-92ad72f50df8.png">|

## `R` 構造体の使用例

- コード例

```swift
import SwiftUI
// `import Rswift` は書きません。

struct SampleView: View {
    var body: some View {
        VStack {
            Text(R.string.localizable.greeting())  // 文字列
                .font(.largeTitle)
                .foregroundColor(Color(R.color.primary))  // 色

            Image(R.image.icon)  // 画像
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 200)
        }
    }
}

struct SampleView_Previews: PreviewProvider {
    static var previews: some View {
        SampleView()
    }
}

```

- プレビュー

<img width="300" alt="プレビュー" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/4523229c-ab5e-45d2-66c9-4f2c406d3be6.png">

# `R.xxx` を省略して書きたい場合

まず、従来の R.Swift では、以下のように Typealias を使うことで、`R.xxx` を省略して書くことができました。

```swift
typealias L10n = R.string.localizable
typealias Image = R.image
typealias Color = R.color
```

R.Swift 7.x 以降では、 `R` が `_R` 構造体のインスタンスになったことにより、以下のように変数として定義することで、同様の機能を果たすことができます。


```swift
let l10n = R.string.localizable
let image = R.image
let color = R.color
```

:::note info
インフォメーション
・省略形の変数名は、私は上記のように定義してみましたが、この辺りはお好みで。
・なお `L10n` とは、localization の lとn の間に10文字あることからついた名称です。類似ライブラリの SwiftGen では、 `L10n` という表記が採用されているので、真似してみました。
:::

## `R.xxx` を省略して書いた場合の使用例

- コード例

```swift
import SwiftUI
// `import Rswift` は書きません。

struct SampleView: View {
    var body: some View {
        VStack {
            Text(l10n.greeting())  // 省略形を使った文字列
                .font(.largeTitle)
                .foregroundColor(Color(color.primary))  // 省略形を使った色

            Image(image.icon)  // 省略形を使った画像
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 200)
        }
    }
}

struct SampleView_Previews: PreviewProvider {
    static var previews: some View {
        SampleView()
    }
}

```

よりすっきりしました。

# `R.generated.swift` の所在

> `R.generated.swift` ファイルを、手動で生成する必要はありません。

と記載しましたが、それではこのファイルは一体どこにあるのでしょうか？
`R` の定義に飛ぶと、確かにこのファイルは存在しています。

まず、右側カラムの "Show the File inspector" を確認したところ、"Not Applicable" （該当なし）でした。
次に、左側カラムの検索バーで、ファイル名や `_R` などを検索ワードにして探しましたが、ヒットしませんでした。
プロジェクトファイル内にない :thinking: ...？？ということで、以下の方法でやっとファイルの所在がわかりました。

画像のように、Xcode の `R.generated.swift` 内で、右クリックしポップアップメニューを表示し、 `Navigate` > `Show in Finder` をクリックします。

<img width="600" alt="探し方" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/a32cc5dc-ac77-2b15-69fe-d5fee56117a2.png">

Finder が開きました。階層が深いです。

<img width="600" alt="Finder" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/f0a63eff-5d59-5104-ac34-d4d94b969d07.png">

パスを確認したところ以下のようなパスでした。
アプリに内包されているのではなく、ユーザーディレクトリの `Library/Developer/Xcode/DerivedData/` の中に生成されていることがわかりました。

> /Users/{ユーザー名}/Library/Developer/Xcode/DerivedData/{アプリ名}-hawjwftgyaobilfxndsomwxfakir/SourcePackages/plugins/{アプリ名}.output/{アプリ名}/RswiftGenerateInternalResources/{アプリ名}/Resources/R.generated.swift 


## `R.generated.swift` ファイルを手動で生成する方法

なお、`R.generated.swift` ファイルを手動で生成することもできます。
ただし、ツールによる自動生成ファイルはGit管理に入れるべきではない、各自で管理すべき、という考え方があるので、私は今のところ用途は思いついてません。

プロジェクト上で右クリックし、 `RswiftGenerateResourcesCommand` をクリックします。

<img width="300" alt="RswiftGenerateResourcesCommand" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/41e6e16d-98ee-4329-e095-8027d6eda50a.png">

`Run` をクリックします。

<img width="800" alt="RswiftGenerateResourcesCommand" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/6e6e291a-8bce-18a4-0df7-181a68a8003d.png">

Finder を開くと、プロジェクトの最上位階層に `R.generated.swift` ファイルが生成されているのが確認できます。

<img width="300" alt="RswiftGenerateResourcesCommand" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/4c765172-e076-cef9-4a0d-836e40abec2b.png">

# 最後に

以上、R.Swiftのプラグインの導入方法の説明でした。
ご覧いただきありがとうございます。

# 参考リンク

- https://github.com/mac-cain13/R.swift
- [R.swift 7 and typealias #769](https://github.com/mac-cain13/R.swift/issues/769)
- [7.x: usage in typealias #778](https://github.com/mac-cain13/R.swift/issues/778)