The previous post was a simple list displaying an array of strings.
Now, let's build up this project a little bit, shall we?
Download the project
Download the project with the finished feature, and I'll explain what changed and how does it work now.
We had a pretty much basic folder structure in the first part, the initial project default layout:
Now, there's a place for everything. What I did was to create a folder for each kind of class responsibility.
As we are using the MVVM pattern, we need at least:
- A Model
- A View
- A View Model
Using MVVM basically defines that:
- We have a model to store our model properties
- We have a view to display our model and receive user interaction
- We have a viewmodel that will handle user interaction coming from the view, and send model data to the view
search dev.to for more mvvm info
The View
The project is still displaying a list of products, but now data is coming from the viewmodel.
struct ProductListView: View {
//MARK: - view model
@ObservedObject var viewModel = ProductListViewModel()
var body: some View {
NavigationView {
List {
ForEach(viewModel.productList) { product in
Text("Description: " + product.description)
}
}
.navigationBarItems(trailing: Button(action: {
self.viewModel.addNewProduct()
}, label: {
Text("Add new product")
} ))
}
}
}
The first version we simply put our array of strings inside the view. But now, our view is referencing a variable inside the viewmodel class.
Notice that the viewmodel is labeled as a @ObservedObject
. This means that the view is observing the class, at any change of published variables these changes will reflect in our view.
The Model
struct Product : Identifiable {
//MARK: - Properties
var id = UUID()
var description: String
}
extension Product {
//MARK: - Default initialization
init() {
self.description = "New product"
}
}
The model is pretty straightforward:
- There's the description property where we can save the product description value
- and a default initialisation, so that we don't have to write property values every time we want to create a new product.
The ViewModel
protocol ProductListViewModelProtocol {
//MARK: - Protocol definition
var productList: [Product] {get}
func addNewProduct()
}
final class ProductListViewModel : ProductListViewModelProtocol, ObservableObject {
//MARK: - Published properties
@Published var productList: [Product] = []
init() {
productList.append(Product(description: "iPhone"))
productList.append(Product(description: "Macbook Pro"))
}
}
extension ProductListViewModel {
//MARK: - Functions implementations
func addNewProduct() {
productList.append(Product())
}
}
Here's where happens all the data and actions flow.
- We have a protocol to define the class capabilities
- A observable class, to enable this class be observed
- I also added a function
addNewProduct()
so that we can add a new product with the app running, and see the changes reflect in our view thanks to the observable feature.
And that's it.
Hit the play button, and now you'll see the same screen working, with an additional button on the right upper corner.
Click the button to add new products and enjoy.
Top comments (0)