final class PostsViewModel: BaseViewModel {
// ...
// MARK: - Input
struct Input {
let postTrigger: Observable<Void>
init(_ postTrigger: Observable<Void>) {
self.postTrigger = postTrigger
}
}
struct Output {
let postList: Driver<[PostModel]>
let isPostListEmpty: Driver<Bool>
init(_ postList: Driver<[PostModel]>,
_ isPostListEmpty: Driver<Bool>) {
self.postList = postList
self.isPostListEmpty = isPostListEmpty
}
}
// ...
}
InputpostTrigger: post 를 받아오는 역할을 하는 트리거Observable 을 사용viewWillAppear 와 collectionView 의 refreshControl 이 있음Observable.merge(~~) 로 구현OutputpostList: postTrigger 에서 트리거가 전달되면 VM 에서 API 호출 후 [PostModel] 받아옴PostsDataSource 에 데이터를 뿌려줌PostsDataSource 에서 사용하기 위해 id 를 추가한 PostModel 형태로 가공해서 건내줌isPostListEmpty: postList 가 비어있으면 emptyView 를 띄우는지를 나타내는 Bool 값postList 가 비어있는지 확인하면 되기 때문에 간단하게 구현final class PostsViewModel: BaseViewModel {
// ...
// MARK: - Custom Functions
func transform(input: Input) -> Output {
let postList = input.postTrigger
.startWith(LoadingView.showLoading())
.flatMapLatest { _ -> Observable<[PostDTO]?> in
self.getPosts()
}
.map { postDTO -> [PostModel] in
guard let postDTO = postDTO else {
LoadingView.hideLoading()
return [PostModel]()
}
var postList = postDTO.map { PostModel(id: UUID(), post: $0) }
LoadingView.hideLoading()
return postList
}
.asDriver(onErrorJustReturn: [])
let isPostListEmpty = postList
.map { $0.isEmpty }
.asDriver(onErrorJustReturn: true)
return Output(postList, isPostListEmpty)
}
}
transformInput 을 Output 으로 전환하는 함수
postList 는 postTrigger 에서 트리거를 getPosts() 함수를 통해 flatMapLatest 에서 [PostDTO] 값을 받아옴
map 에서 [PostDTO] 를 [PostModel] 로 바꿈 → DiffableDataSource 에서는 identifiable 한 무언가가 필요하기 때문에 PostDTO 에 id 를 추가한게 PostModel
다 완료되면 postList 의 타입인 Driver 로 전환
isPostListEmpty 는 postList 에서 바로 판단 가능
final class PostsViewController: RxBaseViewController<PostsViewModel> {
// ...
override func bind(viewModel: PostsViewModel) {
self.confiugreDataSource()
let viewWillAppear = viewModel.viewWillAppear
.asObservable()
// refreshControl 추가할 예정
let input = PostsViewModel.Input(viewWillAppear)
let output = viewModel.transform(input: input)
output.postList.drive(onNext: {
self.loadSnapshotData(with: $0)
}).disposed(by: disposeBag)
}
// ...
}