MVP 架构模式示例。 Swift
MVP architecture pattern example. Swift
我想学习经典的 MVP 架构模式,为此尝试在 Swift 上实现天气应用程序。我从理论上了解了它应该如何工作,但实际上停留在基本理解上。现在我有一个模型:
型号
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
}
查看
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)
}
}
}
主持人
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
}
}
}
}
在 Presenter
中,我从网络服务接收数据,但我无法理解如何使用此数据更新 View
(如何在 Presenter
中实施协议),因为 View
不应该知道模型,但在我的例子中它会知道(任何实现经典 MVP 的想法都将不胜感激!
第二个问题:如何在Presenter
中实现协议得到Model
(如我从https://www.youtube.com/watch?v=qzTeyxIW_ow截取的图片所示)
您可以试试这个,在 MVP 中,presenter 将负责更新视图,因此请修改您的 presenter 以拥有视图 属性。这里的视图只包含 WeatherController 实例。
就 MVP 而言,UIViewController subclasses 实际上是视图而不是演示者。
class WeatherPresenter : WeatherViewPresenter {
unowned let view: WeatherView
let weather: WeatherModel
required init(view: WeatherView, weather: WeatherModel) {
self.view = view
self.weather = weather
}
func updateWeatherView() {
//...update properties on your weather view
self.view.setTemperature(self.weather.temperature)
}
}
例如,要更新温度标签,有一个协议来设置温度值。您可以使用多种方法来设置多个属性,或者为天气视图中的所有 UI 元素设置一个方法。
protocol WeatherView: class {
func setTemperature(temp: String)
//same for pressure, humid etc
}
现在为天气预报器写一个协议
protocol WeatherViewPresenter {
init(view: WeatherView, weather: WeatherModel)
func updateWeatherView()
}
现在您已经为天气设置了演示器 class,您可以像这样使用它
class WeatherViewController : UIViewController, WeatherView {
var presenter: WeatherViewPresenter!
override func viewDidLoad() {
super.viewDidLoad()
let model = //your weather model
presenter = WeatherPresenter(view: self, weather: model)
}
func setTemperature(temp: String) {
self.temperatureLabel.text = temp
}
}
获取天气数据后,只需调用self.presenter.updateWeatherView()
即可更新天气视图。
更多详细信息,请refer
改变
func showWeather(data: WeatherModel)
至
func showWeather(temperature: String, pressure: String, humidity: String)
将这些字符串的构造从View 移到Presenter。这样,视图仍然不知道模型。
Presenter 不应直接与完整视图对话,只能与协议对话。
我想学习经典的 MVP 架构模式,为此尝试在 Swift 上实现天气应用程序。我从理论上了解了它应该如何工作,但实际上停留在基本理解上。现在我有一个模型:
型号
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
}
查看
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)
}
}
}
主持人
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
}
}
}
}
在 Presenter
中,我从网络服务接收数据,但我无法理解如何使用此数据更新 View
(如何在 Presenter
中实施协议),因为 View
不应该知道模型,但在我的例子中它会知道(任何实现经典 MVP 的想法都将不胜感激!
第二个问题:如何在Presenter
中实现协议得到Model
(如我从https://www.youtube.com/watch?v=qzTeyxIW_ow截取的图片所示)
您可以试试这个,在 MVP 中,presenter 将负责更新视图,因此请修改您的 presenter 以拥有视图 属性。这里的视图只包含 WeatherController 实例。
就 MVP 而言,UIViewController subclasses 实际上是视图而不是演示者。
class WeatherPresenter : WeatherViewPresenter {
unowned let view: WeatherView
let weather: WeatherModel
required init(view: WeatherView, weather: WeatherModel) {
self.view = view
self.weather = weather
}
func updateWeatherView() {
//...update properties on your weather view
self.view.setTemperature(self.weather.temperature)
}
}
例如,要更新温度标签,有一个协议来设置温度值。您可以使用多种方法来设置多个属性,或者为天气视图中的所有 UI 元素设置一个方法。
protocol WeatherView: class {
func setTemperature(temp: String)
//same for pressure, humid etc
}
现在为天气预报器写一个协议
protocol WeatherViewPresenter {
init(view: WeatherView, weather: WeatherModel)
func updateWeatherView()
}
现在您已经为天气设置了演示器 class,您可以像这样使用它
class WeatherViewController : UIViewController, WeatherView {
var presenter: WeatherViewPresenter!
override func viewDidLoad() {
super.viewDidLoad()
let model = //your weather model
presenter = WeatherPresenter(view: self, weather: model)
}
func setTemperature(temp: String) {
self.temperatureLabel.text = temp
}
}
获取天气数据后,只需调用self.presenter.updateWeatherView()
即可更新天气视图。
更多详细信息,请refer
改变
func showWeather(data: WeatherModel)
至
func showWeather(temperature: String, pressure: String, humidity: String)
将这些字符串的构造从View 移到Presenter。这样,视图仍然不知道模型。
Presenter 不应直接与完整视图对话,只能与协议对话。