Sucha's Blog ~ Archive for January, 2021

21年1月24日 周日 22:52

Swift(2)

又写了一个多月的 Swift,除了刚开始时的修修补补,慢慢扩展到页面框架部分,不过这个部分我还是不够熟悉,一部分在于我还是沿用项目之前的 ViewModel,另外一部分,很多业务细节还没能深入理解。

虽然这次的标题是 Swift(2),实际内容大部分是 RxSwift 及 ViewController 的结合,以及一些 UI 层级的实践心得。

页面框架

先说一下我们的网络层,搭建了类似 Moya 的网络层框架,基本上是够用了,但相比之前用的 Model 网络层,这里浅浅的封装,就不会有单独的 model 管理器了。简洁是简洁了很多,但是数据层面转换和粘合就得在 ViewController 处理,带来了 ViewController 的膨胀。比如因为用了 RxSwift,同一份数据,有时需要多次 transform,subscribe,这些可都在 ViewController 里面。

我曾经想过这些代码放在 ViewModel 里面会不会好一些,但我上次也许也有提到,这里的 ViewModel,更像是一个 Driver.System 的状态机,初始状态是 initial,之后是 Signal -> Driver 的状态切换,通过一个 reduce 函数检查 ViewModel 绑定的 struct 结构来判断到底应该 loading、setResult 还是其他,如果弄懂了这个,页面的状态处理就很清晰了。

只是这个 ViewModel 只负责将 app 外的数据,transform 为页面状态数据,不涉及到 UI element 数据的 transform,这是跟之前 ViewModel 的区别。ViewModel 带回来的页面状态数据,最终会在 ViewController 中 transform 并 binding、drive UI element,这个过程有时需要做很多的粘合工作,流程也会相当复杂。

另外,UI 层级方面,已有较为复杂的页面,通常 UI View 就好几层,一层一层的 UIStackView 包裹里面的自定义子 view,将需要传递的数据链路,通过 binder 传递出来,即便是 View,都跟 RxSwift 框架直接绑定了。

说一下对这个的理解,我觉得是没必要,因为这个 binder 或者 driver,其实都只算是单向的数据传递,传递出来的时候用就好,传递进去的时候,感觉其实没那么必要的了。

以上提到的,觉得最复杂的还是 ViewModel 及其 Driver.System,基本上抄了几遍,这段时间除了 K 线 ViewController 没有修改过,其他页面多少接触了一点。

目前的页面框架工作得还可以,通用性也还行,只是觉得业务复杂度还是太靠近 ViewController 了。而且当前的框架,ViewController 绑定 TableView 被封装得很厚重,仅支持单种 cell 的 TableView,不知道当时这个模版构建的时候是怎么想的。

还有 TableView 的 DataSource,依赖了 RxDataSource,在 TableView 上,其实不支持 HeaderView 的数据流绑定,还得用回系统提供的 delegate 方式,不伦不类的,还不如全部都用系统的方式呢,因为这个模版框架,将 createCell 的部分,dataSOurce 的数据创建部分,放在了 TableViewCell 里面,这个我是非常不认同的。

我总觉得 Cell 有复用的可能,两者结合不应该那么紧密,即便有 protocol 作为粘合,有时候还是觉得抽象过了,没必要。

这段时间还将 Carthage 的库切换到了静态库上,模拟器运行节省了不少时间,但这个改进在真机上几乎觉察不出来。

做了这部分的心得是,我们依赖的第三方库实在是太多了,这也造成了我们启动慢,因为打包好的 App 就有 150M+。比如我们的数据库,为何要用 Realm 呢,是因为 ORM 方便吗,还是因为它更快,总觉得还不如用系统提供的 SQLite3 好了,或者浅浅地封装一层一层,比如 GRDB 就好。

因为这个库太大了,打包的时候都可以看到打的慢。

UI 层级

学习使用 UIStackView,其实这个我在几年前就有做了一个基于 frame 计算的 StackView 框架,可惜是公司财产,不能开源出来(显然我也没有源码)。

UIStackView 使用有些前提,一方面需要 addArrangedView 添加进来,但是如果只是删除 ArrangedView,其实还在 subviews 里面。

另一方面,每个 view 需要有自己的 size,以及 hugging、compress 优先级,要不感觉最后计算宽度大小的时候,总是不准确。

还有学会了在 tableview 的 header view 上面放置复杂的 UI 层级,这个 tableView 的 header view,不支持 AutoLayout,只能是指定 frame 高度。

但是呢,又能通过将这个 view systemLayoutSizeFittingSize 拿到高度,设置给 frame 来确定这个 tableview header view 的高度。

还有 table view 的 cell 是可以不指定高度的,通过 AutoLayout 计算出来,但是呢,collection view 不可以。

这段时间因为对这些 UI 规则不熟悉,浪费了很多时间,有时想着,还不如我来设置 frame 呢,工作早就做完了。

另外,复杂一点的首页等等 ViewController,各种 NSLayout warning,见怪不怪,设置符合 AutoLayout 的规则,太难了。

哦,对了,我们有两套 layout 的库,一个是 SnapKit,一个是 TinyConstraint,常常是混用的状态,真的有点混乱。

--

大概先这样吧。