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

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

実行環境

  • Xcode9.2
  • carthage 0.26.2

【やったこと】CarthageでRxSwiftのフレームワークをいれた

標準的なCarthageでのインポート方法を実行していました。

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

github "ReactiveX/RxSwift" ~> 4.0

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

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で4つのフレームワークをインポートしました。

image.png

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

/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

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

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

image.png

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

image.png

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

【追記】2018/01/01

🐶 mono (@_mono)さんさんから指摘があり、RxBlockingはXCTestに依存していないそう。

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

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

RxSwift/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


『 Swift 』Article List