Viperbaseは、IOSプラットフォームで使用するためのViper Architectureの実装です。
このプロジェクトの目的は、Viperの使用と採用を容易にすることを目的としており、このアーキテクチャを操作し、その特徴のために手動作業を可能な限り削減しようとするために必要なすべての設定を促進します。
Cocoapodsは、Cocoaプロジェクトの依存マネージャーです。 ViperbaseをXcodeプロジェクトに統合するには、 Podfileで指定します。
pod 'viper-base' , '~> 2.1' Viperを使用する際にあなたが持つかもしれない最も悪い経験は、このアーキテクチャで必要なすべてのファイル、クラス、プロトコルを自分で作成することです。これは生産性に大きな影響を与え、簡単なタスクに時間がかかります。
Xcodeを使用すると、パーソナライズされたテンプレートを作成できます。このリソースを利用できるように、 Viperbase用のテンプレートを特別に作成することにしました。このテンプレートを使用して、手動作業はもうありません。
テンプレートをインストールして使用するには、このチュートリアルを確認してください。
モジュールはアプリの画面を表します。
Viperのこの実装には、いくつかの特殊性があります。
いくつかのアプローチでは、モジュールの作成タスクをルーターの責任と見なしています。しかし、これはモジュール間のナビゲーションにすでに責任があるため、単一の責任の原則に違反します。
この問題を解決するために、ビルダーが作成されました。モジュールのすべてのコンポーネントを作成し、それぞれの接続を作成することを担当しています。
このようにして、エンティティは、ビジネスロジックのない単純な構造であるため、1つ以上のモジュールで使用できます。
iOSアーキテクチャ、ナビゲーションはuiviewcontrollerから別のuiviewcontrollerに実行されます。このため、ルーターは、ナビゲーションの目的でのみ、現在のモジュールのビューのための再審理を所有し、ビルダーから宛先モジュールのビューを受信する必要があります。
契約は、レイヤー間の通信がどのように行われるかを定義します。モジュールは5つの契約で構成されています。
ビュークラスはこのプロトコルに準拠しています。発表者から表示するコミュニケーションを定義します
// MARK: - View Contract
protocol MyModuleViewProtocol : class {
} プレゼンタークラスはこのプロトコルに準拠しています。ビューからプレゼンターへのコミュニケーションを定義します
// MARK: - View Output Contract
protocol MyModuleViewOutputProtocol : class {
} インタラクタークラスは、このプロトコルに準拠しています。プレゼンターからインタラクターへのコミュニケーションを定義します
// MARK: - Interactor Contract
protocol MyModuleInteractorProtocol : class {
} プレゼンタークラスはこのプロトコルに準拠しています。対話者からプレゼンターへのコミュニケーションを定義します
// MARK: - Interactor Output Contract
protocol MyModuleInteractorOutputProtocol : class {
} ルータークラスはこのプロトコルに準拠しています。プレゼンターからルーターへの通信を定義します
// MARK: - Router Contract
protocol MyModuleRouterProtocol : class {
} final class MyModuleView : UIViewController , VIPERView {
var presenter : MyModuleViewOutputProtocol !
}
// MARK: - MyModuleViewProtocol
extension MyModuleView : MyModuleViewProtocol {
}ビュー契約で定義されているメソッドを実装するだけです。
final class MyModulePresenter : VIPERPresenter {
weak var view : MyModuleViewProtocol !
var interactor : MyModuleInteractorProtocol !
var router : MyModuleRouterProtocol !
}
// MARK: - MyModuleViewOutputProtocol
extension MyModulePresenter : MyModuleViewOutputProtocol {
}
// MARK: - MyModuleInteractorOutputProtocol
extension MyModulePresenter : MyModuleInteractorOutputProtocol {
}ビュー出力契約とインタラクター出力契約で定義されているメソッドを実装する必要があります。
final class MyModuleInteractor : VIPERInteractor {
weak var presenter : MyModuleInteractorOutputProtocol !
}
// MARK: - MyModuleInteractorProtocol
extension MyModuleInteractor : MyModuleInteractorProtocol {
}インタラクター契約で定義されているメソッドを実装する必要があります。
final class MyModuleRouter : VIPERRouter {
weak var viewController : UIViewController !
}
// MARK: - MyModuleRouterProtocol
extension MyModuleRouter : MyModuleRouterProtocol {
}ルーター契約で定義されているメソッドを実装するだけです。
ルーターでは、2つの方法でナビゲーションを実行できます。モジュールをモジュアルに提示するか、モジュールをナビゲーションスタックに押し込むことです。ナビゲーションを実行するには、以下の方法を使用します。
-PresentModule(withview:embedin:amimated:recture :)
この方法は、次のモジュールをモダンに提示します。以下のパラメーターの詳細を確認してください。
withView :ナビゲートするモジュールの表示。embedIn : .navigationControllerまたは.none 。デフォルト値は.noneですanimated :トランジションのアニメーションを実行するかどうか。デフォルト値はtrueですcompletion :トランジションが終了したときに呼び出されるハンドラー。デフォルト値はnilです-PushModule(withView:embedin:アニメーション:)
この方法は、次のモジュールをナビゲーションスタックに押し込みます。現在のモジュールがナビゲーションコントローラーに埋め込まれているか、ナビゲーションスタックの一部である場合にのみ機能します。
withView :ナビゲートするモジュールの表示。embedIn : .navigationControllerまたは.none 。デフォルト値は.noneですanimated :トランジションのアニメーションを実行するかどうか。デフォルト値はtrueですビルダークラスでは、モジュール用のView 、 Presenter 、 Interactor 、 router層用のそれぞれのクラスを指定します。
final class MyModuleBuilder : VIPERBuilder < MyModuleView , MyModulePresenter , MyModuleInteractor , MyModuleRouter > {
override class var defaultViewUIType : VIPERViewUIType {
return . storyboard ( name : " MyModuleView " , bundle : nil )
}
}
// MARK: - Builder custom methods
extension MyModuleBuilder {
}また、 defaultViewUITypeプロパティを介して、 View UIのロード方法を定義します。可能な値は3つあります。
. storyboard ( name : " MyModuleView " , bundle : nil ) . nib ( name : " MyModuleView " , bundle : nil ) . none以下の4つのメソッドを使用して、モジュールを構築できます。さらに、モジュールのニーズに応じて、カスタムビルドメソッドを作成できます。
- 建てる() :
モジュールを作成し、 viewとpresenter参照を含むVIPERModule構造体を返します。モジュール間でデータを渡すためにプレゼンターリファレンスを使用できます。
// MARK: - MyModuleRouterProtocol
extension MyModuleRouter : MyModuleRouterProtocol {
func goToNextModule ( ) {
let module = NextModuleBuilder . build ( )
pushModule ( withView : module . view )
}
}-build(viewuitype :) :
この方法は上記の方法のように機能しますが、メソッド呼び出し中にUIタイプを指定できます。この方法は、 typealiasを使用してモジュールビルダーの構成を定義する場合に便利です。
typealias MyModuleBuilder = VIPERBuilder < MyModuleView , MyModulePresenter , MyModuleInteractor , MyModuleRouter >
MyModuleBuilder . build ( viewUIType : . storyboard ( name : " MyModuleView " , bundle : nil ) )テストのニーズに応じて、モジュール通信を中心に単体テストを実行し、 1つ以上のレイヤークラスをock笑することを意図している場合は、この方法を使用することもできます。
import XCTest
class ProjectTests : XCTestCase {
//...
func testModuleCommunication ( ) {
typealias MockModuleBuilder = VIPERBuilder < ModuleMockView , ModuleOriginalPresenter , ModuleOriginalInteractor , ModuleOriginalRouter >
let module = MockModuleBuilder . build ( )
//...
}
} - [非推奨] buildandattachtowindow()
これは、通常、アプリの初期モジュールを起動するために使用される特別なビルド方法であり、 AppDelegateクラスで呼ばれます。
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = InitialModuleBuilder.buildAndAttachToWindow()
return true
}
}
[更新]:最初にモジュールを構築する必要があります。build build()またはbuild(viewUIType:)メソッドのいずれかを使用してから、 attachToWindow()またはattachToWindow(withNavigationController:)新しいメソッドを呼び出します:
window = InitialModuleBuilder . build ( ) . attachToWindow ( ) window = InitialModuleBuilder . build ( ) . attachToWindow ( withNavigationController : true )[重要]:次の主要リリース(v3.0)で非推奨方法を削除することが計画されています
- [非推奨] buildandattachtonavigationcontroller(tabbaritem :)
このメソッドは、モジュールを作成し、ナビゲーションコントローラーに接続し、ナビゲーションコントローラーリファレンスを返します。 Tab Bar Controller内のモジュールを使用する場合は、 tabBarItemパラメーターを使用して、このモジュールのTab Barアイテムを構成できます。
let tabBarController = UITabBarController()
let bookmarksItem = UITabBarItem(tabBarSystemItem: .bookmarks, tag: 0)
let contactsItem = UITabBarItem(tabBarSystemItem: .contacts, tag: 1)
let downloadsItem = UITabBarItem(tabBarSystemItem: .downloads, tag: 2)
tabBarController.viewControllers = [
BookmarksBuilder.buildAndAttachToNavigationController(tabBarItem: bookmarksItem),
ContactsBuilder.buildAndAttachToNavigationController(tabBarItem: contactsItem),
DownloadsBuilder.buildAndAttachToNavigationController(tabBarItem: downloadsItem)
]
[更新]:最初にモジュールを構築する必要があります。build build()またはbuild(viewUIType:)メソッドのいずれかを使用してから、 attachToNavigationController()新しいメソッドを呼び出します。
window = MyModuleBuilder . build ( ) . attachToNavigationController ( )[重要]:次の主要リリース(v3.0)で非推奨方法を削除することが計画されています
データを受信することを期待する特定のモジュールがある場合は、そのモジュールのカスタムビルドメソッドを作成するのが便利です。そうすれば、ビルダーはこのデータをpresenterに渡すことを担当します。
カスタムビルドメソッドを作成するには:
build()メソッドを呼び出す実装を開始します。presenterに渡します。viewを返します。 // MARK: - Builder custom methods
extension NextModuleBuilder {
static func build ( someData : Any , anotherData : Any ) -> MyModuleView {
let module = build ( )
module . presenter . someData = someData
module . presenter . anotherData = anotherData
return module . view
}
}ルーターはこのようにこのビルダーを呼び出すことができます:
let view = NextModuleBuilder . build ( someData : " Example of data " , anotherData : " Another example of data " ) pushModule ( withView : view ) presentModule ( withView : view ) ViperbaseはMITライセンスの下でリリースされます。