Viperbase는 iOS 플랫폼에서 사용하기위한 Viper Architecture의 구현입니다.
이 프로젝트는 바이퍼 사용 및 채택을보다 쉽게 만들어서이 아키텍처를 사용하는 데 필요한 모든 설정을 용이하게하고 그 특성으로 인해 수동 작업이 발생할 수있는 한 가능한 한 많이 줄이려고 노력합니다.
Cocoapods는 코코아 프로젝트의 종속성 관리자입니다. Viperbase를 Xcode 프로젝트에 통합하려면 Podfile 에 지정하십시오.
pod 'viper-base' , '~> 2.1' Viper를 사용할 때 가장 나쁜 경험은이 아키텍처에 필요한 모든 파일, 클래스 및 프로토콜을 직접 작성하는 것입니다. 이것은 생산성에 많은 영향을 미치며 간단한 작업을 수행하는 데 많은 시간이 걸립니다.
Xcode를 사용하면 개인화 된 템플릿을 만들 수 있습니다. 이 리소스를 사용하여 Viperbase를위한 템플릿을 만들기로 결정했습니다. 이 템플릿을 사용하면 더 이상 수동 작업이 없습니다.
템플릿을 설치하고 사용하려면이 자습서를 확인하십시오.
모듈은 앱의 화면을 나타냅니다.
이 Viper의 구현에는 몇 가지 특이성이 있습니다.
일부 접근 방식은 모듈 작성 작업을 라우터 의 책임으로 간주합니다. 그러나 이것은 이미 모듈 간의 탐색을 담당하기 때문에 단일 책임 원칙을 위반합니다.
이 문제를 해결하기 위해 Builder가 만들어졌습니다. 모듈의 모든 구성 요소를 작성하고 각 연결을 수행하는 것이 좋습니다.
이런 식으로 엔티티는 비즈니스 로직이없는 간단한 구조이므로 엔티티는 하나 이상의 모듈에서 사용할 수 있습니다.
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 {
}View Output Contract 및 Interactor 출력 계약 에 정의 된 방법을 구현하면 됩니다.
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 {
}라우터 계약 에 정의 된 방법을 구현하면 됩니다.
라우터에서 내비게이션은 모듈을 모듈로 제시 하거나 모듈을 탐색 스택으로 밀어 넣는 두 가지 방법으로 수행 할 수 있습니다. 내비게이션을 수행하려면 아래 방법을 사용하십시오.
- 현재 모듈 (withview : embedin : 애니메이션 : 완료 :)
이 메소드는 다음 모듈을 모드로 제시합니다. 아래의 매개 변수 세부 사항을 확인하십시오.
withView : 탐색 할 모듈보기.embedIn : .navigationController 또는 .none . 기본값은 .none 입니다animated : 전환 애니메이션을 수행할지 여부. 기본값은 true 입니다completion : 전환이 완료되면 핸들러가 호출됩니다. 기본값은 nil 입니다-PushModule (WithView : Embedin : Animated :)
이 메소드는 다음 모듈을 내비게이션 스택 으로 푸시합니다. 현재 모듈이 탐색 컨트롤러에 포함 되거나 탐색 스택의 일부인 경우 에만 작동합니다 .
withView : 탐색 할 모듈보기.embedIn : .navigationController 또는 .none . 기본값은 .none 입니다animated : 전환 애니메이션을 수행할지 여부. 기본값은 true 입니다 Builder 클래스에서는 모듈에 대한 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 )
}
}- 빌드 (ViewuityPe :) :
이 메소드는 위의 메소드처럼 작동하지만 메소드 호출 중에 UI 유형을 지정할 수 있습니다. 이 방법은 typealias 사용하여 모듈 빌더의 구성을 정의 할 때 편리합니다.
typealias MyModuleBuilder = VIPERBuilder < MyModuleView , MyModulePresenter , MyModuleInteractor , MyModuleRouter >
MyModuleBuilder . build ( viewUIType : . storyboard ( name : " MyModuleView " , bundle : nil ) )테스트 요구에 따라 모듈 통신에 대한 단위 테스트를 수행하고 하나 이상의 레이어 클래스를 조롱하는 경우이 방법을 사용할 수도 있습니다.
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(viewUIType:) attachToWindow(withNavigationController:) 를 사용하여 모듈을 먼저 빌드 해야합니다. 그런 다음 attachToWindow()
window = InitialModuleBuilder . build ( ) . attachToWindow ( ) window = InitialModuleBuilder . build ( ) . attachToWindow ( withNavigationController : true )[중요] : 다음 주요 릴리스 (v3.0)에서 더 이상 사용되지 않은 방법을 제거 할 계획입니다.
- [더 이상 사용되지 않은] BuildAndAttachtAnaVationController (tabbaritem :)
이 메소드는 모듈을 생성하고 내비게이션 컨트롤러에 연결하고 탐색 컨트롤러 참조를 반환합니다 . 탭 바 컨트롤러 내부의 모듈을 사용하려면 tabBarItem 매개 변수를 사용 하여이 모듈의 탭 바 항목을 구성 할 수 있습니다.
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(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 라이센스에 따라 릴리스됩니다.