你有一个大的UIViewController吗? 对许多人来说,是的。 一方面,它与数据一起工作,另一方面-与接口一起工作。
在数百篇有关体系结构的文章中描述了将逻辑与接口分离的任务:MVP,MVVM,VIPER。 它们解决了数据流的问题,但没有回答如何使用界面的问题:在一个地方仍然保留了元素的创建,布局,配置,输入和动画处理。
让我们将视图与控制器分开,看看loadView()如何帮助我们。

iOS的应用程序界面是
UIView
层次结构。 每个
view
的任务:创建元素,自定义,安排位置,设置动画。 从
UIView: addSubview(), drawRect(), layoutSubviews().
类中的方法可以看出
UIView: addSubview(), drawRect(), layoutSubviews().
如果查看
UIViewController
类的方法,则可以看到它管理
view:
加载,响应加载屏幕和用户操作并显示新屏幕。 通常,应该在
UIView
的代码是我们在
UIViewController
子类中编写的,这使其变得太大。 分开吧
loadView()
UIViewController
的生命周期从
loadView()
开始。 简化的实现如下所示:
我们可以重写该方法并指定我们的类。
super.loadView()
不需要被调用!
控制器将加载
CustomView,
将其添加到层次结构中,公开
.frame
。
.view
属性将是我们需要的类:
但是,尽管编译器不知道该类,但认为存在正常的
UIView
。 让我们使用类型转换功能修复此问题:
现在您可以看到
CustomView
变量:
简化关联类型Ruslan Kavetsky建议使用协议扩展来消除代码重复:
protocol ViewSpecificController { associatedtype RootView: UIView } extension ViewSpecificController where Self: UIViewController { func view() -> RootView { return self.view as! RootView } }
对于每个新控制器,您只需通过typealias
指定其UIView
的协议和子类:
UIView子类中的代码
创建和配置控件
字体,颜色,常量和层次结构可以直接在CustomView构造函数中设置:
layoutSubviews()
手动布局的最佳位置是
layoutSubviews()
方法。 每次更改
view
大小时都会调用它,因此您可以依靠
bounds
大小来进行正确的计算:
私人控制,公共财产
如果有时间,那么我将
property
控件设为私有,但是我通过“知识领域”中的公共变量或函数来管理它们。 一个简单的例子:
封装的优点:内部逻辑隐藏在接口后面。 例如,对象的有效性可以由区域的颜色而不是正方形的颜色指示,但是控制器将不了解任何信息。
viewDidLoad()中还剩下什么?
如果使用Interface Builder,则
viewDidLoad()
通常
viewDidLoad()
空。 如果在代码中创建
view
,则需要通过target-action模式绑定它们的动作,添加
UIGestureRecognizer
或绑定委托。
可通过Interface Builder进行自定义
可以通过Interface Builder(以下称为IB)配置用于
view
的子类。
您需要选择
view
对象(而不是控制器)并设置其类。 不必编写自己的
loadView()
,控制器将自己完成。 但是
UIView
仍然必须
UIView
类型。

UIView中的IBOutlet
如果在
view
内部选择控件,则助手编辑器将识别
UIView
类,并将其作为“自动”模式下的第二个文件提供。 因此您可以将
IBOutlet
转移到
view
。

如果不起作用手动打开
CustomView
类,编写
IBOutlet
。 现在,您可以拖动标记并将鼠标悬停在IB中的元素上。

如果使用代码创建接口,则在
init()
之后可以访问所有对象,但是在使用IB时,只有在使用
awakeFromNib()
方法从
UIStoryboard
加载接口之后,才出现对
IBOutlet
访问:
UIViewController中的IBAction
以我的口味,控制器应保留所有用户操作。 从标准:
- 控件的目标动作
UIViewController
委托实现- 区块执行
- 对
Notification
反应
在这种情况下,
UIViewController
仅控制接口。 与业务逻辑相关的所有内容都应从控制器中取出,但这是一个选择:MVP,VIPER等。
目标c
在Objective-C中,您可以完全替换
UIView
类型。 为此,用所需的类声明属性,重写
setter
和
getter
,指定该类:
结束
在GitHub上的示例中,您可以查看一个简单任务的类分离:正方形的颜色取决于其位置(绿色区域为绿色,外部为红色)。
屏幕越复杂,效果越好:减少控制器,将代码转移到其位置。 代码只是移植到
view
,但是封装使交互和读取代码变得容易。 有时,
view
可以与其他控制器一起重用。 例如,iPhone和iPad的不同控制器以自己的方式对键盘的外观做出反应,但这不会更改
view
代码。
每当团队欢迎简化并开始实践时,我在不同的项目中和与不同的人一起使用此代码。 我希望你也喜欢。 所有简单的
UIViewController
!