KMM Как быстро использовать дженерики kotlin?

Извините за мой плохой английский :(

Я хочу создать приложение с KMM и максимизировать общий код. И только то, что я хочу написать дважды, - это UI и Navigation. Итак, я создаю ViewModel в общем коде.

      open class ViewModel<T>(initialState: T) where T : ViewState {

    private val _state = MutableStateFlow(initialState)

    val currentState: T
        get() = stateFlow.value

    val stateFlow: StateFlow<T> = _state

    fun updateState(
        context: CoroutineContext = EmptyCoroutineContext,
        mapping: (currentState: T) -> T
    ) { GlobalScope.launch(context) { _state.emit(mapping(_state.value)) } }
}

Где ViewState просто

      interface ViewState

который используется для реализации в запечатанном классе, который описывает текущее состояние представления. Когда он изменяется, пользовательский интерфейс получает изменения и обновления. Состояние может выглядеть так (первый бесплатный общедоступный API, который я нашел, возвращает случайное изображение собаки):

      sealed class DogImageViewState : ViewState {
    object Loading : DogImageViewState()
    data class Content(val image: String) : DogImageViewState()
}

ХОРОШО

Итак, я создаю конкретную ViewModel для обмена логикой между iOS и Android.

      class DogImageViewModel(initialState: DogImageViewState) : ViewModel<DogImageViewState>(initialState) {

    private val interactor : GetDogImageUrlInteractor by dogDi.instance()

    init {
        getImage()
    }

    fun reload() {
        updateState { DogImageViewState.Loading }
        getImage()
    }

    private fun getImage() {
        GlobalScope.launch(ioDispatcher) {
            val image = interactor.getImageUrl()
            updateState { (it as? Content)?.copy(image = image) ?: Content(image = image) }
        }
    }
}

Просто, понятно? Viewmodel инициализируется с загрузкой и сразу же начинает загрузку изображения. После загрузки изображение переходит в новое состояние. При обновлении действий точно так же

В Android использование очень простое, Jetpack Compose может collectAsState StateFlow и больше нечего делать, просто опишите ui с состоянием

Проблема в iOS

Мы должны «соединить» наблюдаемую модель для iOS. iOS имеет ObservableObject механизм и я расширил его

      class ObservableViewModel<T : ViewState>: ObservableObject {

    @Published var state : T
    
    init(viewModel: ViewModel<T>) {
        self.state = viewModel.currentState
        viewModel.onChange { newState in
            self.state = newState as! T
        }
    }
}

Выглядит неплохо. Общий класс для ViewState... Теперь я могу использовать его со SwiftUI! О нет...

Когда я пытаюсь использовать ObservableViewModel в коде я получаю ошибку

          @StateObject var vm = ObservableViewModel<DogImageViewState>(viewModel: DogImageViewModel(initialState: DogImageViewState.Loading()))

Тип DogImageViewState не соответствует протоколу ViewState

Но точно соответствует !!!

Когда я перехожу к определению DogImageViewState я вижу дальше

      __attribute__((swift_name("DogImageViewState")))
@interface DogDogImageViewState : DogBase <DogSharedViewState>
@end;

Похоже, совсем не соответствует. Что это Base<ViewState> (DogBase, потому что функция Dog строится в отдельной структуре dog и DogSharedViewState из-за ViewState, объявленного в shared)? Почему не просто ViewState?

Как объяснить быстрому, что DogSharedViewState и то же самое?

0 ответов

Другие вопросы по тегам