过去几天投入了比较多的时间在学习和实践 SwiftUI 上,真正用它来做点可以用的东西。实践是检验一个东西最好的方式,通过这几天的实践,我对 SwiftUI 的热情正式被浇灭。于是,本文准备严肃地探(pi)讨(ping)一下 SwiftUI 的现状。
SwiftUI 之 Context Menu 自定义缺失的问题
昨天用 SwiftUI 写一个「收藏夹」的 demo,用到了 Context Menu。然而,我怎么也做不到,给 Delete 操作弄上红色的警示。
后来我才发现,SwiftUI 根本无法自定义这个。
如图:Delete 操作无法自定义成红色。
在认识到这个问题后,我摆正了对 SwiftUI 的态度,我觉得,它还没办法做和 UIKit 同等功能的完整的 App。它可能适合做 Prototype,毕竟用它确实很快。或者在局部的页面里,也可以用 SwiftUI 来达到效果。
然后,很快我又遇到了一个问题,这个问题让我对 SwiftUI 做 Prototype 的期望,都打了折扣。
SwiftUI 之 TabView + List View 持续刷新的问题
先看代码,几乎所有常用的内容型 App 都会有这个设计,那就是 TabView(TabBar)+ List(TableView)。
import SwiftUI
struct ContentView: View {
var body: some View {
TabView() {
List {
ForEach(0..<100) {
Text("\($0)")
}
}
.tabItem {
VStack {
Image("first")
Text("First")
}
}
.tag(0)
Text("Second View")
.font(.title)
.tabItem {
VStack {
Image("second")
Text("Second")
}
}
.tag(1)
}
}
}
这是一段普通的不要再普通的代码,App 有两个 Tab,其中一个 Tab 有一个 View,里面有个 List,有 100 行内容。有如下的运行效果:
乍看之下是没有任何问题的,但是这里有一个非常严重的可用性问题:假如你把 List 滚动到某一行,比如 50 行,点一下 Second Tab,再回来,状态不见了——List 被重置了。
起先我以为是我的问题,但是没道理啊,代码简单到我都没有引入任何状态!后来我搜到了类似的汇报,就在 Apple Developer Forums 上: TabView reload all content constantly 。
看了这个依然没有被解决的帖子,我的心是凉凉的。就在遇到上个问题后,我对 SwiftUI 的预期已经放到了做 Prototype 的程度,现在我觉得,连 Prototype 也做不成了。
GitHub 上有一个仓库,记录了 SwiftUI 的一些比较有名的 Bug: swiftui-bugs ,有些还有 Workaround。看完这些资料后,我发了一个状态:
SwiftUI 这样子,大概版本号只能叫 0.3 吧…实践过后,终于比较深刻地认识到了:Swift 发生过的事情,在 SwiftUI 上再次发生了!
以后 Apple 推出的软件产品,版本号自动除以 3~10 左右,才能约等于正式版(以 1.0 做正式版标准的话)。
对 SwiftUI 的重新评估
很显然,SwiftUI 是不完善的,但是我没想到是这么的不完善。根据我从 Swift 1.0 beta 开始折腾 Swift 的经历,我觉得如果这个时候选择拥抱这个技术,会比从 Swift 1.0 就开始拥抱更痛苦——甚至可能做不好一个可用的产品。
不过,SwiftUI 在特定场景依然有用武之处:假如你的 App(或 Prototype),用到了大量自定义的设计、动效,你根本不打算用系统原生的 TabView、Alert 之类的,SwiftUI 可能是非常合适的——参考 @MengTo 用 SwiftUI 做出的各种成果。
现阶段要不要选择 SwiftUI,就看开发者本人,想从中得到什么了。如果想做一款 Production-Ready 的产品,可能会花费比 Swift 1.0 那会更多的精力。
Swift 在 2018Q4,正式超过 Objective-C,成为 Apple 生态圈开发者使用的首选语言,这个过程花了 4 年多。
SwiftUI 要成为 Apple 生态圈开发者首选的 UI 框架,我觉得,5 年上下,也是一个乐观保守的评估。
那就让我们三五年后再来看这篇文章吧!
SwiftUI的复杂度比Swift低不少,乐观估计两三年后会比较完善。Combine还是比较不错的,比Rx更简洁。
SwiftUI目前应用确实不乐观,在观望哈。