使MVC再次出色!
使用泛型,协议和扩展摆脱大型视图控制器
本文的副本也可在此处获得
Model-View-Controller是一种非常常见的软件结构,用于在Apple生态系统中创建应用程序。
尽管MVC是一个简单的概念,但是开发人员经常会错过使用它并将其转换为MVC的想法。 代表“ Massive View Controller”结构。
在这篇文章中,我们将看到如何通过使用一些简单的技术(如泛型,协议,扩展,便捷的初始化程序等)使MVC再次变得出色,让我们开始吧!
我们的应用程序是一个非常简单的应用程序,只有一个屏幕:登录屏幕,用户可以在其中输入其电子邮件和密码,并且该应用程序将在控制台中将其打印出来。
首先,我们将摆脱所有邪恶的源头,情节提要😈
尽管Apple提倡Storyboard作为为其生态系统开发用户界面的标准方法,但Storyboard仍然存在以下主要问题:
- 性能下降和编译时间。
- 它们不是git友好的,由于其XML性质,它们使团队工作更加艰苦。
- 故事板在运行时失败,而不是在编译时失败,这使它们成为大量未知错误和问题的来源。
- 和更多 …
就个人而言,每次在项目中使用情节提要或Xib文件时,我都会遇到可伸缩性问题。
但是,当我尝试以编程方式编写我的UI代码时,视图控制器变得更大,更难维护,从而无法实现与Massive View Controller对抗的全部目的defeat
1.子类化UIView和UIViewController
2.将所有UI和布局代码从视图控制器中移开。
3.使用扩展来组织视图控制器
4.使用便捷的初始化程序在一行中初始化和设置公共UI元素。
子类化UIView
我们将创建一个名为View的新基类,此子类将从现在开始使用,而不是UIView
类视图:UIView {覆盖init(frame:CGRect){
super.init(frame:框架)
setViews()
layoutViews()
}是否需要初始化?(编码器aDecoder:NSCoder){
super.init(编码器:aDecoder)
setViews()
layoutViews()
} ///在这里设置您的视图及其子视图。
func setViews(){
backgroundColor = .white
} ///在此处布置子视图。
func layoutViews(){}}
子类化UIViewController:
与使用View一样,我们将创建另一个名为ViewController的新基类,从现在开始将继承并使用它,而不是UIViewController
类ViewController :UIViewController {
覆盖func loadView(){
视图= V()
} var customView:V {
返回视图为! V
}}
一起登录示例
LoginView.swift
协议LoginViewDelegate:类{
func loginView(_视图:LoginView,didTapLoginButton按钮:UIButton)}
类LoginView:查看{
弱var委托:LoginViewDelegate?var emailAddress:字符串{
让文字= emailTextField.text
返回文本吗?.trimmingCharacters(in:.whitespacesAndNewlines)?? ”
}
var密码:字符串{
返回passwordTextField.text? ”
}
私人懒惰变量emailTextField:UITextField = {
让textField = UITextField()
textField.placeholder =“电子邮件地址”
textField.keyboardType = .emailAddress
返回textField
}()
私人懒惰的var passwordTextField:UITextField = {
让textField = UITextField()
textField.placeholder =“密码”
textField.isSecureTextEntry = true
返回textField
}()
私人懒惰var loginButton:UIButton = {
let button = UIButton(类型:.system)
button.setTitle(“ Login”,用于:.normal)
返回按钮
}()覆盖func setViews(){
super.setViews()addSubview(emailTextField)
addSubview(passwordTextField)
addSubview(loginButton)
loginButton.addTarget(self,action:#selector(didTapLoginButton(_ :)),for:.touchUpInside)
}覆盖func layoutViews(){
//在此处布置子视图,请考虑使用SnapKit,
太神奇了!
}
}
//标记:-动作
私人扩展名LoginView {@objc func didTapLoginButton(_按钮:UIButton){
委托?.loginView(自己,didTapLoginButton:按钮)
}
}
LoginViewController.swift
类LoginViewController:ViewController {覆盖func viewDidLoad(){
super.viewDidLoad()
customView.delegate =自我
}
}
//标记:-LoginViewDelegate
扩展名LoginViewController:LoginViewDelegate {func loginView(_视图:LoginView,didTapLoginButton按钮:UIButton){
print(“电子邮件地址:\(customView.emailAddress)”)
print(“密码:\(customView.password)”)
}
}
奖金
使用便捷的初始化程序停止一次又一次地写相同的代码:
扩展UITextField {便利init(
占位符:字符串,
keyboardType:UIKeyboardType = .default,
isSecureTextEntry:Bool = false){
self.init()
self.placeholder =占位符
self.keyboardType =键盘类型
self.isSecureTextEntry = isSecureTextEntry
}
}
扩展UIButton {便利init(
类型:UIButtonType = .system,
标题:字符串?,
图片:UIImage?){
self.init(type:type)self.setTitle(标题,用于:.normal)
self.setImage(image,for:.normal)
}
}
新的LoginView
协议LoginViewDelegate:类{
func loginView(_视图:LoginView,didTapLoginButton按钮:UIButton)
}类LoginView:视图{弱var委托:LoginViewDelegate? var emailAddress:字符串{
返回emailTextField.text?.trimmingCharacters(in:.whitespacesAndNewlines)?? ”
} var密码:字符串{
返回passwordTextField.text? ”
}私人懒惰变量emailTextField:UITextField = {
返回UITextField(占位符:“电子邮件地址”,keyboardType:.emailAddress)
}()私有惰性var passwordTextField:UITextField = {
返回UITextField(占位符:“密码”,isSecureTextEntry:true)
}()私有惰性var loginButton:UIButton = {
返回UIButton(标题:“登录”,图像:无)
}()覆盖func setViews(){
super.setViews()
addSubview(emailTextField)
addSubview(passwordTextField)
addSubview(loginButton)
loginButton.addTarget(self,action:#selector(didTapLoginButton(_ :)),for:.touchUpInside)
}覆盖func layoutViews(){...}
}
结论
1.保持布局代码远离视图控制器
2.使用private可以防止视图控制器无法访问您的UI代码,除非有很好的理由不这样做。
3.创建基本的UIView和UIViewController子类,并使用泛型和协议,以使该死的viewDidLoad方法保持干净!
4.使用便捷的初始化程序来初始化UI元素,并将其属性设置为一行。
然后去哪儿?
- 继续第二部分 ,我们将在此基础上处理键盘事件。
- 请参阅Github上的示例Xcode项目