• Start with the MVVM architecture
  • For example: What can RxSwift do

Start with the MVVM architecture

MVC is the mainstream client programming framework at present. In iOS development, the system implements a public view class: UIView and a controller class: UIViewController for us.

During the development process, you must have written the code to format the data for the View in the Controller, why we so naturally put the code to format the data in the Controller, a straightforward answer is that M and V are not suitable. The code that formats the data certainly doesn’t fit in the Model, and the View should only be responsible for displaying content to the user. It shouldn’t care what it displays. So, that leaves Controller, and we just shove it in, and as our UI gets more complex, controllers get fatter and harder to test, let alone reuse.

The MVC hierarchy is clear, but if used incorrectly, a lot of code is concentrated in controllers, and viewControllers have a high probability of being filled with code that doesn’t fit in either the Model or the View. After the project was too large, the optimization of Controller never stopped, and some schemes were summarized:

1. Separate UITableView's Data Source into another class. 2. Separate the data acquisition and conversion logic into a separate class. 3. Separate the logic of the assembled control into another class. The summary is that controllers only put code that can't be reusedCopy the code

MVVM is a relatively new architecture relative to the history of MVC. MVVM was first proposed by Microsoft WPF and Silverlight architect John Gossman in 2005 and is used in Microsoft software development. MVC had been around for over 20 years, so you can see how different the ages were.

MVC:

Model <-> Controller <-> View

MVVM:

Model <-> ViewModel <-> Controller <-> View
Copy the code

As you can see, this View Model is new to MVVM. On the one hand, it provides all the data interfaces for the Controller instead of the Model; On the other hand, it writes data back to Model instead of Controller. This allows the Controller to focus only on the transition from data to view. As we will see in future videos, this can significantly improve the size and testability of controllers.

1. The View should not know any Controller details, it is just a whiteboard for displaying content, and it will display whatever is given to it. Whether it’s MVC, whether it’s MVVM, this is a rule to follow;

2. The Controller should not know any Model details.

3. View Model owns Model. In the original MVC pattern, the Model was owned by the Controller, but in MVVM, the Model was owned by the View Model.

4. The Model should not know about the View Model that owns it.

MVVM in use, usually also use bidirectional binding technology, so that when the Model changes, the ViewModel will automatically update, and when the ViewModel changes, the View will automatically change. Therefore, the MVVM pattern is sometimes referred to as the Model-view-binder pattern. In iOS, this can be achieved using KVO or Notification technology because of the complexity of KVO code, which is derived from ReactiveCocoa, Rxswift’s tool. They are responsive programming.

Before we get started, we need to understand the following concepts: Functional Programming and React Programming. The combination of them makes binding data very easy.

In Functional Programming, functions become first-class citizens, having the same functions as objects, such as passing as parameters, returning as values, and so on.

React Programming, we used to have weak event-based processing, now we have input-based processing (called Signal in ReactiveCocoa). The input can also be used for various combinations or filters through functional programming, showing a variety of flexible processing.

Stateless is the devil of a function. Stateless makes the function more testable.

Immutable data is unchangeable, making software logical and easily testable.

The core concept of RxSwift is that an Observer subscribes to an Observable. An observer responds to data, or a sequence of data, emitted by an Observable. The same is true in the real world: you wait for your boss to make arrangements to respond to his commands, and you sit at home waiting for your mother to make orders to eat, and you eat.

For example: What can RxSwift do

Before we learn about RxSwift, let’s look at a few simple examples of what RxSwift can do

    Observable.combineLatest(firstName.rx.text, lastName.rx.text) { "\ [$0!). \ [$1!)."}.map { "Greetings, \ [$0)" }
        .bind(to: greetingLabel.rx.text)
        .disposed(by: rx.disposeBag)
Copy the code

Here’s an official example of what he did:

1. Combine the firstName and lastName text values with Spaces and pass the result to the next use. 2. Using the map method, prefix the values obtained in the previous step with a Greeting, and pass the values to the next step. 3. BindTo is the binding, bind the values in the previous step to the text of the greetingLabelCopy the code

The end result: When the user enters any characters in the firstName and lastName textFiles, the greetingLabel responds, displaying the latest input Greeting+firstName+””+lastName

  • GreetingLabel is an Observer subscribing to an Observable firstName and lastName. GreetingLabel responds to user input received by firstName and lastName

If the traditional way to implement the UITextField listening needs to implement how:

1. Agency

// Need to inherit UITextFieldDelegate
override func viewDidLoad(a) {
    super.viewDidLoad()
    firstName.delegate = self
    lastName.delegate = self
}
    
var firstNameString = ""
var lastNameString = ""
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
    if(textField == firstName){
        firstNameString = textField.text!
    }
    if(textField == lastName){
        lastNameString = textField.text!
    }
    greetingLabel.text = "Greetings,  \(firstNameString) \(lastNameString)"
    return true
}
Copy the code

2. KVO mode

override func viewDidLoad(a) {
    super.viewDidLoad()
    firstName.addObserver(self, forKeyPath: "text", options: .new, context: nil)
    lastName.addObserver(self, forKeyPath: "text", options: .new , context: nil)
    view.addSubview(firstName)
    view.addSubview(lastName)
    view.addSubview(greetingLabel)
}
    
// Non-real-time changes
var firstNameString = ""
var lastNameString = ""
override func observeValue(forKeyPath keyPath: String? , of object: Any? , change: [NSKeyValueChangeKey : Any]? , context: UnsafeMutableRawPointer?) {
    if (object as! UITextField == firstName) {
        firstNameString = firstName.text!
    }
    if (object as! UITextField == lastName) {
        lastNameString = lastName.text!
    }
    greetingLabel.text = "Greetings,  \(firstNameString) \(lastNameString)"
}
Copy the code

3. Notification method

override func viewDidLoad(a) {
    super.viewDidLoad()
    firstName.addTarget(self, action: #selector(fieldChange), for: .editingChanged)
    lastName.addTarget(self, action: #selector(fieldChange), for: .editingChanged)
    view.addSubview(firstName)
    view.addSubview(lastName)
    view.addSubview(greetingLabel)
}
    
var firstNameString = ""
var lastNameString = ""
@objc func fieldChange(textField: UITextField){
    if(textField == firstName){
        firstNameString = textField.text!
    }
    if(textField == lastName){
        lastNameString = textField.text!
    }
    greetingLabel.text = "Greetings,  \(firstNameString) \(lastNameString)"
}
Copy the code

4. Add monitoring directly

override func viewDidLoad(a) {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(fieldChange), name: .UITextFieldTextDidChange, object: firstName)
    NotificationCenter.default.addObserver(self, selector: #selector(fieldChange), name: .UITextFieldTextDidChange, object: lastName)
    view.addSubview(firstName)
    view.addSubview(lastName)
    view.addSubview(greetingLabel)
}
    
var firstNameString = ""
var lastNameString = ""
@objc func fieldChange(notify:NSNotification){
    let textfield = notify.object as! UITextField
    if (textfield == firstName){
        firstNameString = textfield.text!
    }
    if (textfield == lastName){
        lastNameString = textfield.text!
    }
    greetingLabel.text = "Greetings,  \(firstNameString) \(lastNameString)"
}
Copy the code

I believe you have seen the idea of RxSwift and its simple code charm, don’t worry, next we will learn how to learn from RxSwift official documentation, and then we will practice to make an app, learn the knowledge points while doing it.

【RxSwift Practice Series 2/3】 Thinking in RX-Create and Drive