【RxSwift】RxBlockingとRxTestはテストのフレームワークだからCarthage入れる時は注意しよう！

Carthageで[RxSwift](https://github.com/ReactiveX/RxSwift)のRxBlockingフレームワークとRxTestフレームワークとプロジェクトにインポートしようとしてハマりました。
この２つのフレームワークはテスト用のフレームワークなのにメインのアプリターゲットに取り込んでしまったのが原因。
忘れないように解決方法を記事に残そうと思います。

# 実行環境
* Xcode9.2
* carthage 0.26.2


# 【やったこと】CarthageでRxSwiftのフレームワークをいれた
標準的なCarthageでのインポート方法を実行していました。

まず`Cartfile`を作り、RxSwiftを指定します。

```
github "ReactiveX/RxSwift" ~> 4.0
```

updateでcarthageでRxSwiftフレームワークをクローン&ビルドします。

```bash
carthage update --platform iOS
...
*** Checking out RxSwift at "4.1.0"
*** xcodebuild output can be found in /var/folders/h7/mls39jf56szdt9yhcmhtv5b80000gn/T/carthage-xcodebuild.yf00eV.log
*** Building scheme "RxCocoa-iOS" in Rx.xcworkspace
*** Building scheme "RxSwift-iOS" in Rx.xcworkspace
*** Building scheme "RxBlocking-iOS" in Rx.xcworkspace
*** Building scheme "RxTests-iOS" in Rx.xcworkspace

```

RxCocoa、RxSwift、RxBlocking、RxTestsの4つのフレームワークがビルドされました。

これをアプリプロジェクトに指定していきます。
プロジェクトエディターのGeneral > Linked Frameworks and Librariesで４つのフレームワークをインポートしました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/31587/692b4b07-3274-c7e6-cfc4-65431e6d13e4.png)

また、Build PhaseにRun Scriptを追加し、下記コマンドも追加、input fileに4つのフレームワークのパスの追加もしました。

```bash
/usr/local/bin/carthage copy-frameworks
```

```
$(SRCROOT)/Carthage/Build/iOS/RxCocoa.framework
$(SRCROOT)/Carthage/Build/iOS/RxSwift.framework
$(SRCROOT)/Carthage/Build/iOS/RxBlocking.framework
$(SRCROOT)/Carthage/Build/iOS/RxTest.framework
```

# 【問題発生】XCTestがないという実行時エラーでアプリが落ちる

ところがこの状態でアプリをビルドすると実行時エラーでアプリが落ちてしまいます。

コンソールから出力されたエラーはこちら。

```

dyld: Library not loaded: @rpath/XCTest.framework/XCTest
  Referenced from: /Users/xxxxxx/Library/Developer/CoreSimulator/Devices/7A8D7F6F-7F02-4524-9AB6-511490751CC1/data/Containers/Bundle/Application/090C5FE7-7B5F-4609-B11C-552C46C145F2/MVVMExample.app/Frameworks/libswiftXCTest.dylib
  Reason: image not found
```

エラー内容は「libswiftXCTest.dylibがないため、XCTest.frameworkがロードできませんでした」というもの。

XCTestフレームワークってどこから来たのだろうと首をかしげて調査に時間がかかってしまいました。


# 【解決方法】RxBlockingとRxTestはテストターゲットに指定しよう

考えて見ればRxBlocking、RxTestsはテスト用のフレームワークでXCTestフレームワークに依存しているとのことでした。
しかしメインアプリのターゲットではXCTestフレームワークはインポートされていないのでXCTestフレームワークが見つからずアプリが落ちるようです。

なのでRxBlocking、RxTestsはテストターゲットにインポートが必要です。
アプリターゲットで指定していたRxBlocking、RxTestsを消してテストターゲットに移し替えるました。

まず、メインアプリターゲットのGeneral > Linked Frameworks and LibrariesでRxBlockingとRxTestのフレームワークを消しました。
RxCocoaとRxSwiftのみを残した状態にします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/31587/cd81f66d-5970-d366-77f8-d8d30c12f06e.png)

また同じくメインアプリターゲットのBuild PhasesのRun ScriptでRxBlockingとRxTestのinput fileのパスを消しました。

そして、テストターゲットにRxBlocking、RxTestsをインポートします。
ところで、テストターゲットのプロジェクトエディターのGeneralにはLinked Frameworks and Librariesの項目がありません。
なのでBuild Phases > Link Binary With Librariesで指定をしてあげます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/31587/2aba4057-23a3-3a6f-d354-8faf94c8b55c.png)

アプリターゲットと同じく、Run Scriptを追加してフレームワークのコピー指定も忘れずにします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/31587/724cfc7a-04b0-7784-edc4-c5dee930de19.png)


こうすることでビルドが上手くいくはずです！

# 【追記】2018/01/01 
[🐶 mono (@_mono)さん](https://twitter.com/_mono)さんから指摘があり、RxBlockingはXCTestに依存していないそう。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">RxBlockingのみ入れた場合は試しました？RxTestはダメですがRxBlockingはメインアプリターゲットに含めても問題にならないという認識です🧐<br>(メインアプリにRxBlockingを入れて使うことの是非は別として)</p>&mdash; 🐶 mono  (@_mono) <a href="https://twitter.com/_mono/status/947658897711443968?ref_src=twsrc%5Etfw">2018年1月1日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


試したところRxBlockingをアプリターゲットに含めてビルドができました。

ただしRxBlockingは公式ではテスト用のみを目的にしたフレームワークだそうです。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">RxBlockingは使うこと自体は完全に非推奨になってますね(　´･‿･｀)以前、メインアプリで便宜的に同期的に結果が欲しいときに一瞬使おうとしましたがやめました🐶<a href="https://t.co/WLTWXDKzy0">https://t.co/WLTWXDKzy0</a><br>&gt; Don&#39;t use these operators in production apps. These operators are only meant for testing purposes.</p>&mdash; 🐶 mono  (@_mono) <a href="https://twitter.com/_mono/status/947665400531058688?ref_src=twsrc%5Etfw">2018年1月1日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


[RxSwift/RxBlocking](https://github.com/ReactiveX/RxSwift/tree/master/RxBlocking)

> Don't use these operators in production apps. These operators are only meant for testing purposes.
> これらのオペレーターを本番用アプリで使用しないでください。これらのオペレーターはテストの目的で作られました。(筆者訳）

RxBlockingは「アプリターゲットに入れられるけど非推奨」とのことです。
まとめるとアプリターゲットとテストターゲットに入れるフレームワークは以下となります。

|ターゲット|フレームワーク|補足|
|:------|:-------|:-------|
|アプリターゲット|RxCocoa |UIKitのクラスのエクステンションを提供するのであると便利。 |
|アプリターゲット|RxSwift| RxSwiftの大元フレームワーク|
|テストターゲット|RxBlocking|アプリターゲットに入れられるけど非推奨。テストに使いましょう。|
|テストターゲット|RxTests|XCTest依存でアプリターゲットに入れられない。テストに使いましょう。|

# 参考
↓は同じくRxBlockingをメインターゲットにしてXCTest.frameworkがないために実行時エラーになった方のイシューです。
[dyld: Library not loaded: @rpath/XCTest.framework/XCTest · Issue #1717 · Carthage/Carthage](https://github.com/Carthage/Carthage/issues/1717)