iOSアプリでフレームワーク間のブリッジを作成する方法

アプリのコードが次のようであれば…

「アプリのその部分をエクスポートしたいのですが、スパゲッティプレートのようにアプリの他の部分に関連付けられています!」

依存しすぎるアプリの一部をエクスポートしようとしています

作業中のアプリの一部をモジュール化し始めたとき、壁にぶつかりました。

サービス(実際には追跡サービス)を別のフレームワークにエクスポートしたかった。問題は、このサービスがアプリにほとんど結び付けられていないことでした。アプリに深く固定された別のサービスを使用していた他のサービスを使用していました。

追跡サービスをエクスポートするには、新しいフレームワークでサービス全体をリファクタリングおよびリメイクする必要がありました。

しかし、実際には、これを行う時間がなかったため、回帰テストは悪夢であり、他の多くの理由により、どの会社でも可能性がありました(プロセス、予算、期限)。
そのため、すべてをリファクタリングせずにアプリのこの部分をエクスポートする方法を見つける必要がありました。

具体的な例から始めましょう!

ここで、物事がどのように機能するかを学び、理解する最良の方法は、実践することです! (この投稿の最後に、この例のGithubリポジトリを提供します)
コンテキストを設定してみましょう。画面が2つしかない小さなアプリがあります。

  • ホーム画面
  • 支払い画面(その画面をフレームワークにエクスポートしたい)

支払いページには、カード番号を入力するTextField、および支払いボタンが含まれています。ボタンを押すと、支払いが開始されます。
しかし!課題は支払い方法にあります。少し前に思い起こした何らかの理由で、支払いサービスをエクスポートできないとしましょう。

ホーム画面と支払い画面

したがって、2つの異なるターゲットで宣言されたこれらの2つの画面があります。ホーム画面はメインアプリターゲットで宣言され、支払い画面はPaymentModuleと呼ばれる別のモジュールで宣言されます。また、メインアプリターゲットで次のようにPaymentServiceが宣言されています。

支払い方法は、依存しすぎているためアプリから抽出できない方法です。しかし、私たちは支払いモジュールからそれを使いたいです。

PaymentモジュールにPaymentViewControllerが定義されています。PaymentServiceを呼び出そうとすると、このサービスはモジュールにないためエラーが発生します。モジュール内にメインターゲットをインポートすることはできません(これはナンセンスです)

では、PaymentViewControllerからこのメソッドをどのように使用するのでしょうか?

モジュールでプロトコルを定義する

これが私たちの橋になるでしょう。メインアプリターゲットで使用する内容を記述するメソッドを使用して、モジュール内でプロトコルを定義する必要があります。

したがって、payメソッドを使用してPaymentServiceProtocolという名前のプロトコルを定義します。

アプリでのプロトコルの実装

次に、PaymentServiceにこのプロトコルに準拠するように指示する必要があります。これを追加するだけです。

「プロトコルで宣言されたメソッドがこの拡張機能に実装されていないのはなぜですか?」

プロトコルに準拠する場合、そのプロパティとメソッドを実装する必要があります。ここでのコツは、プロトコルのメソッド名が、先ほど宣言したPaymentServiceのメソッド名とまったく同じであることです。このようにして、システムは、プロトコルメソッドにアクセスするときにPaymentServiceクラスで宣言されたメソッドpayを使用する必要があることを認識します。

2つの部分をリンクする

ここで、2つの部分を結合する必要があります。
HomeViewControllerから「Go to payment page」ボタンをタップすると、PaymentViewControllerがインスタンス化されます。その時点で、PaymentServiceクラスへの参照を渡しますが、モジュール内の支払いコントローラーはこれをPaymentServiceProtocolタイプとして認識します。

ここにトリックがあります:

PaymentService.selfを渡していますが、モジュール内のコードにはPaymentServiceProtocol.Typeが表示されています。
これで、モジュールからアプリで定義された有料メソッドを呼び出すことができます!

ブリッジを使用する

これで、作成したブリッジを非常に簡単に使用できます。

didTapPayButtonメソッドは、Payボタンをタップするたびに呼び出されます(正しい音ですか?)。 23行目を確認してください。アプリから取得したプロトコル参照でpayメソッドを呼び出しています。

PaymentServiceはこのプロトコルに準拠しているため、システムはPaymentService.swiftで定義されているメソッドpay内のコードを実行します。

つまり、最初はモジュールから呼び出すことができなかったメソッドを使用しています!これでブリッジが設定されました。

支払いボタンをタップすると、次のようになります。

メインターゲットに含まれる支払い方法を支払いモジュールから使用する

結論

結論として、アプリのコンポーネントをフレームワークにエクスポートする場合、このブリッジ方法を使用できます。

この手法を使用すると、アプリのその部分をフレームワークにエクスポートする必要があるが、何らかの理由ですべてをエクスポートできない場合に、ボウルから麺を切り取ることができます。

フレームワーク内のコンポーネント全体を取り出す前に、たとえば時間があるときに、これは一時的な解決策だと思います。 (このシナリオでは、いつか支払いモジュール内で支払い方法をエクスポートする必要があります)

ユニコーンや派手なものがある理想的な世界では、私たちはそのようなことをしないと認めています。コンポーネント全体をエクスポートしたいのですが、何度も言ったように、これは常に可能とは限りません。

このプロジェクトのGithubリポジトリはこちらで確認できます。ブリッジがどのように行われるかを確認し、自分で試してみてください。
この投稿がお役に立てば幸いです。お気軽にご質問ください。

このストーリーは、Mediumの最大の起業家精神に関する出版物であるThe Startupに掲載され、続いて+442,678人が続きます。

ここで私たちのトップ記事を受け取るために購読してください。