Created
May 24, 2020 09:32
-
-
Save fumiyasac/ea76497ebea6a1f67595f014c90bae4d to your computer and use it in GitHub Desktop.
PropertyWrapperを利用したDependendyInjectionの例(各ドメイン側)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// (1) APIRequestManager.swift | |
// Infra層部分 | |
import Foundation | |
import RxSwift | |
// MARK: - Protocol | |
protocol APIRequestProtocol { | |
func getAnnoucements() -> Single<AnnouncementListResponse> | |
} | |
// MARK: - APIRequestManagerProtocol | |
extension APIRequestManager: APIRequestProtocol { | |
// お知らせ一覧表示用のAPIリクエスト処理の実行 | |
func getAnnoucements() -> Single<AnnouncementListResponse> { | |
let annoucementListsEndPoint = EndPoint.announcement.getBaseUrl() | |
return executeAPIRequest( | |
endpointUrl: annoucementListsEndPoint, | |
httpMethod: HTTPMethod.GET, | |
responseFormat: AnnouncementListResponse.self | |
) | |
} | |
} | |
// (2) AnnoucementRepositoryImpl.swift | |
// Domain層部分 | |
import Foundation | |
import RxSwift | |
// MARK: - Protocol | |
protocol AnnoucementRepository { | |
// お知らせ一覧表示用のAPIリクエストを実行する | |
func requestAnnouncementDataList() -> Single<AnnouncementListResponse> | |
} | |
final class AnnoucementRepositoryImpl: AnnoucementRepository { | |
// MARK: - Properties | |
@Dependencies.Inject(Dependencies.Name(rawValue: "APIRequestProtocol")) private var apiRequestManager: APIRequestProtocol | |
// MARK: - AnnoucementRepository | |
func requestAnnouncementDataList() -> Single<AnnouncementListResponse> { | |
return apiRequestManager.getAnnoucements() | |
} | |
} | |
// (3) AnnouncementUseCaseImpl.swift | |
// UseCase層部分 | |
import Foundation | |
import RxSwift | |
// MARK: - Protocol | |
protocol AnnouncementUsecase { | |
// お知らせ一覧取得処理を実行する | |
func execute() -> Single<AnnouncementListResponse> | |
} | |
final class AnnouncementUseCaseImpl: AnnouncementUsecase { | |
// MARK: - Properties | |
@Dependencies.Inject(Dependencies.Name(rawValue: "AnnoucementRepository")) private var annoucementRepository: AnnoucementRepository | |
// MARK: - AnnouncementUsecase | |
func execute() -> Single<AnnouncementListResponse> { | |
return annoucementRepository.requestAnnouncementDataList() | |
} | |
} | |
// (4) AnnouncementViewModel.swift | |
// ViewModel層部分 | |
import Foundation | |
import RxSwift | |
import RxCocoa | |
protocol AnnouncementViewModelInputs { | |
// 初回のデータ取得をViewModelへ伝える | |
var initialFetchTrigger: PublishSubject<Void> { get } | |
// PullToRefreshでのデータ更新をViewModelへ伝える | |
var pullToRefreshTrigger: PublishSubject<Void> { get } | |
} | |
protocol AnnouncementViewModelOutputs { | |
// JSONから取得した表示用データを格納する | |
var announcementItems: Observable<Array<AnnouncementEntity>> { get } | |
// 取得処理の実行結果を格納する | |
var requestStatus: Observable<APIRequestState> { get } | |
} | |
protocol AnnouncementViewModelType { | |
var inputs: AnnouncementViewModelInputs { get } | |
var outputs: AnnouncementViewModelOutputs { get } | |
} | |
final class AnnouncementViewModel: AnnouncementViewModelInputs, AnnouncementViewModelOutputs, AnnouncementViewModelType { | |
var inputs: AnnouncementViewModelInputs { return self } | |
var outputs: AnnouncementViewModelOutputs { return self } | |
// MARK: - Properties (for AnnouncementViewModelInputs) | |
let initialFetchTrigger: PublishSubject<Void> = PublishSubject<Void>() | |
let pullToRefreshTrigger: PublishSubject<Void> = PublishSubject<Void>() | |
// MARK: - Properties (for AnnouncementViewModelOutputs) | |
var announcementItems: Observable<Array<AnnouncementEntity>> { | |
return _announcementItems.asObservable() | |
} | |
var requestStatus: Observable<APIRequestState> { | |
return _requestStatus.asObservable() | |
} | |
// MARK: - Properties | |
private let disposeBag = DisposeBag() | |
// MEMO: 中継地点となるBehaviorRelayの変数(Outputの変数を生成するための「つなぎ」のような役割) | |
// → BehaviorRelayの変化が起こったらObservableに変換されてOutputに流れてくる | |
private let _announcementItems: BehaviorRelay<Array<AnnouncementEntity>> = BehaviorRelay<Array<AnnouncementEntity>>(value: []) | |
private let _requestStatus: BehaviorRelay<APIRequestState> = BehaviorRelay<APIRequestState>(value: .none) | |
// MEMO: このViewModelで利用するUseCase(Domain Model) | |
@Dependencies.Inject(Dependencies.Name(rawValue: "AnnouncementUsecase")) private var announcementUsecase: AnnouncementUsecase | |
// MARK: - Initializer | |
init() { | |
// ViewModel側の処理実行トリガーと連結させる | |
initialFetchTrigger | |
.subscribe( | |
onNext: { [weak self] _ in | |
guard let self = self else { return } | |
self.executeAnnouncementDataRequest() | |
} | |
) | |
.disposed(by: disposeBag) | |
pullToRefreshTrigger | |
.subscribe( | |
onNext: { [weak self] _ in | |
guard let self = self else { return } | |
self.executeAnnouncementDataRequest() | |
} | |
) | |
.disposed(by: disposeBag) | |
} | |
// MARK: - Private Function | |
private func executeAnnouncementDataRequest() { | |
_requestStatus.accept(.requesting) | |
announcementUsecase.execute() | |
.subscribe( | |
onSuccess: { [weak self] data in | |
guard let self = self else { return } | |
self._requestStatus.accept(.success) | |
self._announcementItems.accept(data.result) | |
}, | |
onError: { [weak self] error in | |
guard let self = self else { return } | |
self._requestStatus.accept(.error) | |
} | |
) | |
.disposed(by: disposeBag) | |
} | |
} | |
// (5) AnnouncementViewController.swift | |
// ViewController層部分 | |
final class AnnouncementViewController: UIViewController { | |
// ... (※Dependency Injection部分のみ抜粋) ... | |
// MEMO: お知らせ表示状態をハンドリングするViewModel | |
@Dependencies.Inject(Dependencies.Name(rawValue: "AnnouncementViewModelType")) private var viewModel: AnnouncementViewModelType | |
// ... 以下省略 ... | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment