VIPER and SwiftUI: Model layer By TMarcelin Tutorials - April 4, 2022 Comments: 0 Views: 846 Problem One of our company's projects uses the VIPER architecture. At the time of UIKit, there were no problems with it, but a new "dark" era of SwiftUI has come. Under SwiftUI conditions, "pure" VIPER is not possible. I had to come up with something, because a similar solution on the network did not fit. Theory My idea was as follows: if VIPER uses delegates and reactivity looks at least strange in it, and SwiftUI is just so reactive, you need to make a separate layer that will support reactivity, and at the same time will work as a delegate of the Presenter layer. Why not use reactive variables in Presenter? The answer is that I didn't want to clutter this layer with reactivity. As for me, these layers should be separated and the Presenter should perform its original functions. In this case, there is less confusion and there is a distinction: what happens and on which layer. The name of this layer is Model, which follows from the title of the article. It should work the way the View would work from the side of interaction with the Presenter. That is, accept events and send your own to SwiftUIView. Implementation First, let's analyze the implementation of the Model layer itself. import Combine class SceneModel: ObservableObject { var output: SceneModelOutput! // Реализуем презентер как делегат модели @Published var articlesState: State = .rest { didSet { if articlesState == .loaded { setSpinnerState(isSpin: false) } } } @Published var articles: [Articles] = [] @Published var spinnerState: Bool = false func loadArticles() { output.loadArticles() } func setSpinnerState(isSpin: Bool) { spinnerState = isSpin } } // Реализуем модель как делегат презентера extension SceneModel: SceneModelInput { func setArticlesState(state: State) { articlesState = state } func setArticles(articles: [Articles]) { self.articles = articles } } In the SceneModel we store various states and data that the Presenter prepares for us, in our case these are reactive fields. // Реализуем презентер как делегат модели extension ScenePresenter: SceneModelOutput { func loadArticles() { interactor.loadArticles() } } // Вызываем метод делегата презентера extension ScenePresenter: SceneModelOutput { func articlesLoaded(articles: [Article]) { model.setArticles(articles: articles) model.setArticlesState(state: .loaded) } } In the Presenter, we implement the functionality of the model delegate and, in our case, by receiving an event from the Interactor, we execute functions on the model. import SwiftUI struct SceneView: View { @ObservedObject var output: SceneModel var body: some View { Group { switch output.articlesState { case .loaded: List { ForEach(output.articles) { Text($0.text) } } default: EmptyView() } } .onAppear(perform: { output.loadArticles() }) } } In SwiftUIView we build interaction with the model. In all other modules, everything remains to work in the same way as it worked before. Thus, we get VIPER working in the reactive space with SwiftUI. At the same time, the essence of VIPER in delegation of authority between modules is not violated and the "reactivity" of SwiftUI is preserved.
Directories in iOS: store, update, use Countries, cities, professional areas, languages, currencies - all these are the names of March 31, 2022 Blog
14 Mobile App Trends in 2022 Since its inception, smartphones have become more and more popular every day. Technology is gaining February 26, 2022 Blog
Important little things when developing mobile applications Probably, you have repeatedly searched the markets for a mobile application for some keyword, January 13, 2022 Blog