1

I was testing MVVM Architecture using SwiftUI.

I have rating views for an array of products and a clear button, when the clear button is pressed I want to clear the ratings of all.

On clicking a clear button, I reset the model and update the state to render it on UI, but UI doesn't get updated.

why the Rating is not getting cleared on click of reset button?

protocol ViewModelType: ObservableObject {
    associatedtype Input
    associatedtype State
    
    var state: State { get }
    func trigger(_ input: Input)
    
    var subscriptions: Set<AnyCancellable> { get }
}

class TestViewModel: ViewModelType {
        
    enum Input {
        case initialise
        case clearRating
    }
    
    enum State {
        case idle
        case testData(BagModel)
    }
    
    var subscriptions = Set<AnyCancellable>()
    
    @Published var state = State.idle
    var bag: BagModel?
    
    var products: [ProductModel] = [.init(id: 101, title: "Product 1", rating: 0),
                                    .init(id: 102, title: "Product 2", rating: 0)]
    
    func trigger(_ input: Input) {
        switch input {
        case .initialise:
            bag = BagModel(products: products)
            state = .testData(bag!)
            
        case .clearRating:
            products = [.init(id: 101, title: "Product 1", rating: 0),
                        .init(id: 102, title: "Product 2", rating: 0)]
            bag?.products = products
            state = .testData(bag!)
        }
    }
    
}

extension TestViewModel {
    struct BagModel {
        var products: [ProductModel]
    }
    
    struct ProductModel: Identifiable, Equatable {
        var id: Int
        var title: String
        var rating: Int
    }
}


struct TestView: View {
    
    @StateObject var viewModel = TestViewModel()
    
    var body: some View {
        VStack {
            switch viewModel.state {
            case .testData(let bags):
                VStack(alignment: .center, spacing: 20) {
                    ForEach(bags.products) { product in
                        Item(title: product.title, rating: product.rating)
                    }
                    
                    Button {
                        viewModel.trigger(.clearRating)
                    } label: {
                        Text("Clear Rating")
                    }

                }
                
            default:
                EmptyView()
            }
        }.onAppear {
            viewModel.trigger(.initialise)
        }
    }
}

extension TestView {
    struct Item: View {
        
        var title: String
        @State var rating: Int
                
        var body: some View {
            Group {
                Text(title)
                RatingStarView(rating: $rating)
            }
        }
    }
}


NOTE: I was referring to this article https://quickbirdstudios.com/blog/swiftui-architecture-redux-mvvm/

Anirudha Mahale
  • 2,526
  • 3
  • 37
  • 57

0 Answers0