見出し画像

RxSwift ViewModelのデータをSwiftUI Viewで表示

こんにちは🐹
今回も引き続きSwiftUIの備忘録を書いていきます📝

概要

今まで開発してきたアプリはRxとUIKitを使用してきました。
これに加えてこれから新規で追加する機能はできればSwiftUIを使って開発することになりました。

新しい画面(View)をSwiftUIにすれば、ViewModelもSwiftUIにしない以上、既存のRxを使ってデータのやりとりをしていたViewModelとの接触は、必要不可欠なことになります。

そしたらどうやってRx ViewModelのデータをSwiftUI Viewで表示できるかについて私がやってみた方法を共有したいと思います。

実装​

まずは、ViewModelの方から見ていきましょう。
コメントアウトで一連の流れと説明をしてますので参考にしてください。

import RxRelay
import RxSwift
// 1. SwiftUIのプロトコルを使うのでSwiftUIをimportする
import SwiftUI

protocol SomeViewModelInput {
   var viewDidLoad: PublishRelay<Void> { get }
}

protocol SomeViewModelOutput {
   ...省略...
}

protocol SomeViewModelType {
   var input: SomeViewModelInput { get }
   var output: SomeViewModelOutput { get }
}

// 2. クラス宣言部でObservableObjectを継承します。
final class SomeViewModel: SomeViewModelType, SomeViewModelInput, SomeViewModelOutput, ObservableObject {
    
    // 3. Publishedでデータを格納&監視する変数を宣言
    @Published var someWords: [String]
    
    var input: SomeViewModelInput { return self }
    var output: SomeViewModelOutput { return self }
    
    private let disposeBag = DisposeBag()
    
    init(someWordsStore: SomeWordsStore) {
        // 4. Publishedで宣言した変数をイニシャライザーの中で初期化を行う
        someWords = []
        
        ...中略...
        
        // 5. 読み込んだ値を変数に格納させ、かつ値の変更を監視するように
        Observable
           .combineLatest(input.viewDidLoad, someWordsStore.someWords) { $1 }
           .subscribe(onNext: { [weak self] someWords in
               self?.someWords = someWords
           })
           .disposed(by: disposeBag)
    }
    
    ...省略...
}

ViewModelではObservableObjectプロトコルの継承と@Publishedの変数がポイントです!

次はViewを見ていきましょう。

import SwiftUI

struct SomeView: View {
    
    // 1. 値の変更を監視するViewModelを@ObservedObjectで宣言
    @ObservedObject var viewModel: SomeViewModel
    
    var body: some View {
       HStack {
           // 2. ViewModelから読み込んでくる値をTextに表示
           ForEach(viewModel.someWords, id: \.self) { word in
               Text(word)
           }
       }
    }
   
}

View側ではViewModelを@ObservedObjectにすることでデータの読み込み&監視ができるようになります。
これでUIにデータを表示することができるはずです!

最後に

SwiftUIで提供しているプロパティ@ObservedObject@Publishedを使うと、Rxで読み込んできたデータも非同期で簡単にSwiftUI Viewに表示できるようになりますのでRx+SwiftUIで開発する方々はぜひ試してみてください!

参考資料


この記事が気に入ったらサポートをしてみませんか?