天天看点

【iOS 开发】ViewController 减负记录

前言

最近在重构一个以前写的老项目,在尝试给之前的 ViewController 减负,尽量抽离代码到其他文件。

想记录一些东西,看看以后返回来再看能不能有更好的想法;而现在,可以作为一个检验当前代码是否需要优化的一个标准。

整合常量

以前喜欢在 ViewController 的顶部(class 外面)写一些全局变量,这样虽然可以写一次创建的代码,就可以在整个项目的任意地方使用。但是,基本上你不可能只有一个 ViewController,有了这种习惯之后,会让全局变量没有逻辑地分散在不同的代码文件里,不易于管理(甚至可能会出现同一个东西以不同的名字被创建了多次的情况),而且代码可读性会严重降低(因为你看见这个变量的时候,你可能并不知道它是全局的)。

解决起来其实很简单,我当前这个项目的缩写是 GM,于是我建了一个叫 GMConstants 的 Class,把所有之前的全局变量都放到这里,写成 <code>static let</code> 的形式。(除非你真的知道这样没问题,否则不建议写 <code>static var</code>,或创建 GMVariables Class,这样会导致你使用这些量的时候,依然不知道具体这些是什么,因为它们可能被更改过)

比如之前我设定了我这个 App 中使用的所有的灰色都应该是一样的,我写了一个 gmGreyColor 的常量,使用的时候,你可能并不记得这么一个东西是全局的,并且担心除了灰色,还有什么颜色,是不是还有个 gmBlackColor?甚至你可能写了一个意义相同的 gmGrayColor,仅仅是因为 grey 和 gray 同义。而现在,你的使用方式应该是 <code>GMConstants.greyColor</code>——一看便知是什么意思,而且按住 cmd 键,鼠标左击 GMConstants 关键词,你还可以看见你到底创建了几个类似这样的颜色。

当你想写全局变量,或者发现某个局部变量,在不同的地方被多次使用的时候,就该考虑这个问题了。

布尔标记

刚刚提到不建议以整合常量的方式来整合变量,不过后续又发现之前会用这样一种方式来处理逻辑:先写一个值为 <code>false</code> 的布尔变量,以此作为一种标记,后续根据情况来不断地修改该值为 <code>true</code> 或者 <code>false</code> ,来判断某些语句是否应该执行。

虽然目前认为这种方式并不是优雅的写法,因为这样一个布尔标记的作用范围太大了,虽然写代码的时候知道,某种情况 <code>true</code>,另一种情况 <code>false</code>,但以后修改的时候,就要求程序员有全局观才能尝试修改或移除这个标记。

暂时没有想到很好的修改方法,但是认为这种情况下,可以像之前整理 <code>static let</code> 一样来以 <code>static var</code> 的形式来整理这些布尔类型的标记,可能取 class 名为 GMMarks。

另外还可以自定义这些标记的 setter,比如

static var imageSelected:Bool = false
           

我们可以这样自定义 setter:

class func selectImage() {
    GMMarks.imageSelected = true
}
class func deselectImage() {
    GMMarks.imageSelected = false
}
           

语义更清晰易懂

UIView 耦合

self.view.addSubview(view1)
self.view.addSubview(view2)
self.view.addSubview(view3)
           

假如说在 ViewController 里面看到上面这样的代码,同时发现 view1、view2、view3 之间就是简单的一层一层叠加而已,那么我们或许可以向之前一样建一个叫做 GMViews 的 class,然后把这三个 view 的创建都放在

class func xxView (frame frame:CGRect) -> UIView
           

这样一个方法里面,使用时也很简单

let xxView = GMViews.xxView(frame: xx)
self.view.addSubView(xxView)
           

这个时候一定要注意,之前三个 view 在 ViewController 里面创建时,frame 是根据 self.view 这个 view 来写的,frame.origin 是一个 CGPoint,它表示的是相对于父级 view 的相对位置,而不是相对于你的 App 界面的绝对位置,所以抽离这部分代码的时候,确保你的各个 view 的 frame 写对(在支持横屏的时候,是不是还涉及其他问题)。

抽离方法命名问题

MVC 令人诟病的一点是,以前写在 Controller 里面的业务逻辑很臃肿,现在加个 <code>func</code> 关键字就抽离到 Model 里面,导致 Controller 不臃肿了,Model 反倒臃肿了。

所以如果想要从之前臃肿的 ViewController 里面抽离到代码到新的类,一定要注意 Model 的命名问题。

比如说我现在要清理缓存,清理缓存这种事情应该说和当前的 ViewController 是没什么耦合性可言的,完全可以把这部分代码剥离出来,那么如果这时候我根据清理的具体内容不同,抽象出了三个函数:

func clear1() {}
func clear2() {}
func clear3() {}
           

如果直接粗暴地把这三个方法填到一个叫做 GMTools 的类里面,把这些方法都加上 <code>class</code> 关键字,那么以后这个类会越来越杂乱,这和之前没什么分别。

较好的做法应该是把这个类叫做 GMClear,而且尽量调用方法的时候,让方法体内部的逻辑和现在的这个 App 本身没太大关系,把和现在的 App 有直接关系的部分作为参数,让使用者传参调用。

这样下来,或许你可以在这个项目结束的时候,拥有几个可能叫 GMClear、GMSave、GMShare 的类,而且这些类里面的方法和你现在这个 App 没有太多直接联系,那么下一个项目用到这些东西,直接把代码文件复制过去就可以了。

继续阅读