Search code examples
iosswiftdesign-patternsmvp

MVP architecture pattern example. Swift


I want to learn classic MVP architecture pattern and for this try to implement Weather app on Swift. I learned in theory how it should work but practically stuck on basic understanding. For now I have a model:

Model

class WeatherModel: Codable {
    var name: String?
    var main: Main?
}

class Main: Codable {
    var temperature: Float?
    var pressure: Int?
    var humidity: Int?
    private enum CodingKeys: String, CodingKey {
        case temperature = "temp"
        case pressure
        case humidity
    }

View

final class WeatherViewController: UIViewController {
    @IBOutlet weak var cityTextField: UITextField!
    @IBOutlet weak var temperatureLabel: UILabel!
    @IBOutlet weak var pressureLabel: UILabel!
    @IBOutlet weak var humidityLabel: UILabel!

    private var presenter: WeatherPresenter!

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()
        presenter = WeatherPresenter()
        cityTextField.delegate = self
        presenter.delegate = self

    }

    @IBAction func buttonClicked(_ sender: Any) {
        let city = cityTextField.text
        if let city = city {
            presenter.loadWeatherFor(city: city)
        }
    }
}

extension WeatherViewController: WeatherPresenterProtocol {

    // MARK: - WeatherPresenterProtocol

    func showWeather(data: WeatherModel) {
        if let temperature = data.main?.temperature {
            self.temperatureLabel.text = String(temperature)
        }
        if let pressure = data.main?.pressure {
            self.pressureLabel.text = Constants.pressure + String(pressure)
        }
        if let humidity = data.main?.humidity {
            self.humidityLabel.text = Constants.humidity + String(humidity)
        }
    }
}

Presenter

protocol WeatherPresenterProtocol: class {
    func showWeather(data: WeatherModel) // ?
}

final class WeatherPresenter {
    var model: WeatherModel!
    weak var delegate: WeatherPresenterProtocol?

    func loadWeatherFor(city: String) {
        Network.shared.getWeather(city) { [weak self] (weather, error) in
            DispatchQueue.main.async {
                self?.model = weather
            }
        }
    }
}

In Presenter I receive data from a Network Service but I can't understand how to update View with this data (how to implement protocol in Presenter) because View shouldn't know about model but in my case it will know( Any idea to implement classic MVP will be appreciated!

And second question: how to implement protocol in Presenter to get Model (as it is shown in the picture I've taken from https://www.youtube.com/watch?v=qzTeyxIW_ow) enter image description here


Solution

  • Change

    func showWeather(data: WeatherModel)
    

    to

    func showWeather(temperature: String, pressure: String, humidity: String)
    

    Move the construction of these strings from the View to the Presenter. This way, the View remains ignorant of the model.

    The Presenter should not speak directly to the full View, only to the protocol.