Skip to content

Instantly share code, notes, and snippets.

@fumiyasac
Created May 24, 2020 09:32
Show Gist options
  • Save fumiyasac/ea76497ebea6a1f67595f014c90bae4d to your computer and use it in GitHub Desktop.
Save fumiyasac/ea76497ebea6a1f67595f014c90bae4d to your computer and use it in GitHub Desktop.
PropertyWrapperを利用したDependendyInjectionの例(各ドメイン側)
// (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