工作是这样的。
我最近在测验用 SwiftUI 做一个相对杂乱的应用,想看看不使用 UIKit 的转化东西,也就是不用 UIViewRepresentable
和 UIViewControllerRepresentable
,仅靠 SwiftUI 自己能做到什么程度。
刚开始的时候,SwiftUI 写起来确实很爽。DSL 方式的代码让我可以快速地把模糊的概念转化成 UI。但是项目逐步杂乱起来后,就会遇到各种小的问题,比如子视图不更新、手势没反应之类的。这些问题根本可以靠 stackoverflow 或许国外的一些博客处理,它们也在我的预期之中,究竟材料不详细也应该是新结构的通病。
直到今日,在遇到了这样的一个 bug,我有点不由得了…
为了展示这个 bug,让咱们先写一段正常的代码:
class Team: ObservableObject {
@Published var members: [Soldier] = [Soldier(name: "Soldier 0")]
func addSoldier() {
members.append(Soldier(name: "Soldier \(members.count)"))
}
func removeCurrentSoldier() {
if members.count > 1 {
members.removeLast()
}
}
}
struct Soldier {
var name: String
}
struct ContentView: View {
@ObservedObject var team = Team()
var body: some View {
VStack {
ForEach(team.members.indices, id: \.self) { i in
TextField("", text: $team.members[i].name)
}
HStack {
Button("+") { team.addSoldier() }
Button("-") { team.removeCurrentSoldier() }
}
}
}
}
这段代码应该很好了解。ContentView
会展示 team
中保存的战士小队的名单,经过下面的两个按钮可以增减小队的成员,在 TextField
中也可以更新成员的名字。运转起来大致像这样:
在上面这段代码的基础上,假如咱们要给每个战士加一个头像,把
TextField("", text: $team.members[i].name)
改为:
HStack {
Image(systemName: "person.fill")
TextField("", text: $team.members[i].name)
}
再次运转程序,测验删除操作,程序会直接报错退出。。。
甚至当咱们不加上这个 Image
,仅仅是在 TextField
外面套一个 HStack
或 VStack
,也会呈现相同的问题。在 stackoverflow 也有不少人遇到了类似的问题,但回答中提出的 work around 都不适用。
为什么在外面套一个布局容器会影响控件的行为呀!
假如是一般的开源 UI 结构,呈现这种奇葩问题咱们可以跑去社区提 issue,或许测验自己用源码修 bug。但是由于 SwiftUI 是个闭源的结构,貌似就只能给苹果官方提 bug report 了… 这种情况下的反馈速度,实在是不敢让人有所期望… 最高效的办法或许是改掉自己的规划,然后祈求新的方案不会再遇到类似的过错。
尽管我应该仍是会继续完成手头的这个项目,但是这个 bug 极大损伤了我对 SwiftUI 在短期内可以实际应用的信心,由于这样的问题阐明 SwiftUI 缺少的或许不仅仅是完善的文档与配套东西,它内部的一些中心机制还处在不太稳定的状态。在这样的结构上制造应用,无疑是在刀尖上跳舞。不过另一个角度,假如苹果没有很快的修复这些潜在的问题,或许社区中会呈现一系列为 SwiftUI 定制的用于维护状态,然后间接调控生命周期的库,所以说不好这也是开发者们的一些时机。
本文就到这里了,假如你也觉得这个 bug 有点匪夷所思,不妨点个赞~