IOS Programming: Implementing MVVM for prject swift(part 1)

Today we will make a small application, displaying a list of animals, such as photos:

List of types of animals

The first is to download my source code here:

https://github.com/codetoanbug/MVVMSample

I instruct you to download the code with git a little. It's a git command line.

The first is that you open the terminal and type:

git clone https://github.com/codetoanbug/MVVMSample.git

Then you cd to the MVVMSample code folder. The trick is to type the MV CD, pressing the tab button on the keyboard it also commands the following:

CD MVVMSample

Next type to show the entire branch:

git branch -a

You will see branch master, bai1… Each branch will contain the code of 1 post. Here we are only interested in code 1 so you need to switch to the code of lesson 1 by typing as follows:

git checkout bai1

So you already have the code of today's post. It's simple, isn't it?

To implement the MVVM model, we need to grasp through this model how it works.

Let's approach the simplest way. By default, when you create a project, Xcode it renders files according to their MVC standards. M is Model, V is View, and C is Controller. However, here we will often handle logic to get data for the view and display the general view into the ViewController.

If you take that approach, then your table wants data, you have to create data for it in ViewController. Then day after day, this table view adds many new features. For example, when touching each cell on the table, you have to check what the cell is, open the corresponding detail screen. Or in your view controller the boss requires to get data from the server instead of creating a hard data set in it. You have to handle when there is data, how it is displayed, when there is no data, how it is displayed. Then one more beautiful day your boss asked me to display many different types of cells, each cell type 1 different type of data … The longer the code, the harder it is to edit later.

The problem of MVC here is to handle all the logic in view, then the code is much. It's hard to read, irritable, swear, and finally punch your boss and quit 🥲

There are many developers who have been so stressed, silver hair goes a lot after years of pure MVC code. Then they started to get frustrated and wanted to change something to make the job simpler. They immediately think "why not put logical data processing into another file, and the view is merely finding data?" And then they decided to do it. Go to the balcony to smoke, watch the neighbors and keep reading.

This new component they named the View Model – that is, it traffics back and back between the view and the model. The name is very close, isn't it? 🤣

Stop being savage. Here I will show how to implement each part 1 for easy understanding.

First you create a new project using Xcode, name it whatever it is. Go to the Main.storyboard file and drag and drop a tableview, 1 title as pictured:

Drag and drop title and tableview

The next step you create a new AnimalViewController file inherited from UIViewController, choose it manages the interface file you just did. Proceed to drag and drop the links from the view to this UIViewController.

Let's say I drag and drop tableview and get the following code:

 @IBOutlet weak var tableView: UITableView!
 

It's not done, there's tableview, we've got to create a cell for it. So create a MyTableViewCell class inherited from UITableViewCell. And pull it down again! High-paying light 😛

It looks like this:

On the left is the label, on the right is the image.

Remember to auto layout for it. I didn't know how to punch him. Pay attention to the red circle I am lazy so often take this identifier to the name class cell. For easy remembering and copying for convenience. Its purpose is post-reuse.

The code is as follows:

@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var animalImageView: UIImageView!

Then, and now to code clean, you create me a function in AnimalViewController that says the following:

Init table view
    private func initTableView() {
        tableView.register(UINib(nibName: "MyTableViewCell", bundle: nil), forCellReuseIdentifier: "MyTableViewCell")
        tableView.delegate = self
        tableView.dataSource = self
    }

Very basic, here it means that the table registers the cell for a little use. Inherit delegate and datasource functions. Every newbie needs to know. Then throw the jaw into the viewDidLoad function. We haven't seen the model yet. Now this main category.

The first is that you have to create a model to contain my animal data, including a name and a picture. I create code with a struct as follows:


Animal struct {
    let name: String
    let image: String
}

Struct because it's valuable, there's no class. Class for View model.

Then, now we will immediately think about the need for a model view to handle the following jobs:

  1. Create datasource for tableview, definitely throw it into the init function of the model view
  2. Create return functions for delegates and tableview datasources.

Specifically you create the AnimalViewModel file and the code is as follows:

AnimalViewModel class {
    private var anim[Animal]als: 

init() {
        animal[]s = 

Create data source
        animals.append(name: "Alligator", image: "Alligator"))
        animals.append(name: "Anteater", image: "Anteater"))
        animals.append(name: "Armadillo", image: "Armadillo"))
    }

func numberOfRowsInSection(section: Int) -> Int {
        return animals.count
    }

func cellForRowAt(indexPath: IndexPath) -> Animal {
        return animals[indexPath.row]
    }
}

The code is long, but for simplicity, I create data in the local, the following article I will guide to get data from somewhere on the network. The jobs are as follows:

  1. Init creates datasource for tableview
  2. NumberOfRowsInSection function I set to the function of table datasource, the purpose of paying the row number on 1 section
  3. CellForRowAt, too, aims to bind data to cells

And back to the AnimalViewController file, you write me more of this line:

var animalViewModel: AnimalViewModel!

When you're done creating a model view, you have to throw it into the view controller. Then, again to give the code clean, you create a function to handle the model view for it. The code is as follows:

private func bindViewModel() {
        animalViewModel = AnimalViewModel()
    }

Above only 1 line of code is creating a model view. However, the actual projects it has many other settings, such as the closure of the view model. But wait, I'll show you the following.

And now that you need to handle the table view, you write the following code:

AnimalViewController extension: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return animalViewModel.numberOfRowsInSection(section: section)
    }

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "MyTableViewCell") as! MyTableViewCell
        cell.bindData(animal: animalViewModel.cellForRowAt(indexPath: indexPath))
        return cell
    }

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 80
    }
}

The above code is quite clean, the view controller will get data through the model view, and you need to pay attention to what is in it, just view the model you pay me data. Therefore, the view controller no longer has to handle model processing logic. It's like getting married and someone cooking rice.

However, in this example I have a series of white photos, which you can see in the Assets section as pictured:

Photos I stole online

So for the sesame color app, I wrote more coloring extensions from this white photo. Go to the Extensions file to see.

In UIImageView+Extensions I have the following code:

UIImageView extension {
  func setImageColor(color: UIColor) {
    let templateImage = self.image?. withRenderingMode(.alwaysTemplate)
    self.image = templateImage
    self.tintColor = color
  }
}

This paragraph is coloring the image.

In UIColor+Extensions, it is to create a random color for a photo that is different in color:

UIColor extension {
    static func random() -> UIColor {
        return UIColor(
           red: .random(),
           green: .random(),
           blue: .random(),
           Alpha: 1.0
        )
    }
}

Okay, that's basically done. In the next article, I will do more about the request to the server.

Leave a Comment