以下代码运行正常,正如预期的那样,直到我Text
在下面添加了额外的视图Toggle
(在下面的代码中已注释掉)。当我这样做时,我得到了一个Geometry action is cycling between duplicate values.错误,程序最终挂起(在 X86 15.2 上)。它并没有真正挂起,但似乎卡在了某个无限更新循环中,消耗了 100% 的核心并耗尽了 RAM。M3 15.1 上出现了同样的错误,只是还没有能够让它挂起/卡住。
这似乎是一个新的错误,因为 Google 没有返回任何结果。
有人见过类似的事情吗?如果是,这意味着什么?
代码有问题吗?或者这是 SwiftUI 中可能存在错误的征兆?
struct CaptureSizeView: ViewModifier {
@Binding var size: CGSize
func body(content: Self.Content) -> some View {
content
.onGeometryChange(for: CGSize.self) { proxy in proxy.size }
action: { newValue in size = newValue }
}
}
public extension View {
func captureSize(_ size: Binding<CGSize>) -> some View {
modifier(CaptureSizeView(size: size))
}
}
public extension CGSize {
var aspectRatio: CGFloat { self.width / self.height }
}
struct ContentView: View {
@State private var clearSize: CGSize = .zero
@State private var isSquare: Bool = false
var body: some View {
HStack(alignment: .top) {
VStack(alignment: .leading) {
Toggle("Keep Square", isOn: $isSquare).toggleStyle(.switch)
// Uncomment: error "Geometry action is cycling between duplicate values."
// Text("available size: \(clearSize)")
}
.padding()
Divider()
VStack {
Text("Canvas")
.font(.largeTitle)
.fontWeight(.black)
Text("available size: \(clearSize)")
ZStack {
Color.clear
.border(.green)
.captureSize($clearSize)
.overlay {
Canvas { _, _ in
}
.aspectRatio(isSquare ? 1 : clearSize.aspectRatio, contentMode: .fit)
.background(.yellow)
}
}
.padding()
}
}
}
}
通过在 macOS 15.1.1(配备 Apple M1 Pro 的 MacBook Pro)上运行您的代码,我能够重现该问题。
您的视图分为左侧和右侧:
Text
显示大小的输出决定。这是因为文本的宽度大于左侧上方显示的切换控件所需的宽度。ZStack
带有一个Color
(和一个Canvas
作为覆盖的)。当窗口大小改变时,会导致窗口大小
ZStack
改变。当显示新大小时,文本的宽度(可能)与之前显示的大小不同,因为使用比例字体来显示大小。因此,Text
大小的改变会导致大小再次改变ZStack
。大小的最新改变ZStack
会导致宽度再次改变Text
。如此循环往复。要解决这个问题,您需要防止尺寸的变化
ZStack
引起连锁反应,从而导致尺寸的另一次变化ZStack
。