(SwiftUI更改检测)这段代码有什么问题?
在调试我正在使用的应用程序的问题时,我设法将其缩小到以下最小示例:(SwiftUI更改检测)这段代码有什么问题?,swiftui,Swiftui,在调试我正在使用的应用程序的问题时,我设法将其缩小到以下最小示例: class RadioModel: ObservableObject { @Published var selected: Int = 0 } struct RadioButton: View { let idx: Int @EnvironmentObject var radioModel: RadioModel var body: some View { Button(actio
class RadioModel: ObservableObject {
@Published var selected: Int = 0
}
struct RadioButton: View {
let idx: Int
@EnvironmentObject var radioModel: RadioModel
var body: some View {
Button(action: {
self.radioModel.selected = self.idx
}, label: {
if radioModel.selected == idx {
Text("Button \(idx)").background(Color.yellow)
} else {
Text("Button \(idx)")
}
})
}
}
struct RadioListTest: View {
@ObservedObject var radioModel = RadioModel()
var body: some View {
return VStack {
Text("You selected: \(radioModel.selected)")
RadioButton(idx: 0)
RadioButton(idx: 1)
RadioButton(idx: 2)
}.environmentObject(radioModel)
}
}
struct ContentView: View {
@State var refreshDate = Date()
func refresh() {
print("Refreshing...")
self.refreshDate = Date()
}
var body: some View {
VStack {
Text("\(refreshDate)")
HStack {
Button(action: {
self.refresh()
}, label: {
Text("Refresh")
})
RadioListTest()
}
}
}
}
这段代码在我看来相当合理,尽管它显示了一个特殊的bug:当我点击刷新
按钮时,单选按钮停止工作。单选按钮不会刷新,并保留对旧的RadioModel
实例的引用,因此当我单击它们时,它们会更新该实例,而不是Refresh
之后创建的新按钮会导致构建新的RadioListTest
。我怀疑我使用EnvironmentObject
s的方式有问题,但我没有发现任何参考资料表明我所做的是错误的。我知道我可以通过各种方式解决这个问题,强制刷新单选按钮,但我希望能够了解哪些情况需要刷新强制破解,我不能仅仅因为“安全比抱歉更好”就在代码中散布这些,如果每次修改都要重新绘制所有内容,那么性能会非常糟糕
编辑:澄清。在我看来,奇怪的事情是:为什么在
refresh
上重新创建radioisttest
(连同一个新的RadioModel
)并重新评估它的body
,但是创建了RadioButton
,而不评估body
属性,但是使用了前面的正文
。它们都只有一个视图模型作为状态,实际上是相同的视图模型,但一个视图模型作为ObservedObject
,另一个视图模型作为EnvironmentObject
。我怀疑这是我对环境对象的误用,但我找不到任何关于它为什么是错误的参考资料这是有效的:(是的,我知道,你知道如何解决它,但我认为这是“正确”的方法
问题是这一行:
struct RadioListTest: View {
@ObservedObject var radioModel = RadioModel(). <<< problem
struct RadioListTest:视图{
@ObservedObject var radioModel=radioModel()。这是有效的:(是的,我知道,你知道如何解决它,但我认为这是“正确”的方法
问题是这一行:
struct RadioListTest: View {
@ObservedObject var radioModel = RadioModel(). <<< problem
struct RadioListTest:视图{
@ObservedObject var radioModel=radioModel()。
这段代码有什么问题
您的RadioListTest
子视图不会在refresh()
上更新,因为它不依赖于已更改的参数(refreshDate
,在本例中),所以SwiftUI渲染引擎假定它与先前创建的相同,并且不做任何处理:
HStack {
Button(action: {
self.refresh()
}, label: {
Text("Refresh")
})
RadioListTest() // << here !!
}
这段代码有什么问题
您的RadioListTest
子视图不会在refresh()
上更新,因为它不依赖于已更改的参数(refreshDate
,在本例中),所以SwiftUI渲染引擎假定它与先前创建的相同,并且不做任何处理:
HStack {
Button(action: {
self.refresh()
}, label: {
Text("Refresh")
})
RadioListTest() // << here !!
}
请再次检查代码好吗?它不可编译…错误:无法编辑泛型参数“Content”inferred@Chrisyeh抱歉,必须删除该参数,不再使用它。请再次检查您的代码好吗?它不可编译…错误:无法编辑通用参数“内容”inferred@Chris是的,对不起,护理人员er必须被删除,它不再被使用。如果所有状态都是全局的和单实例的,那么双实例就没有问题。但这对于更大的应用程序来说是不可扩展的。如果有一个复杂的应用程序具有导航功能,并且可能有大量的放射科医生,我无法在根视图中初始化所有内容,然后传递它关闭后,我需要能够装入子视图状态。例如,考虑表示文件系统导航,每个单选按钮都是您可以选择导航到的目录(有点像MacOS“打开文件”对话框)。我已经通过您的第一个注释理解了这一点;)我正在考虑其他解决方案……但这不是唯一的解决方案“第一个问题”不再是……这是第二个问题;)要清楚:每次父对象更改时都可以重新创建模型(并重置其状态),这不是我要调查的问题。我希望在更改与其关联的环境对象
实例时重新评估按钮的主体
(当刷新日期发生变化时会发生这种情况),但问题不是“我如何才能使它工作”,而是“我做错了什么?”".yeh如果所有状态都是全局和单实例,那么双实例就没有问题。但对于更大的应用程序来说,这并不能扩展。如果有一个具有导航功能的复杂应用程序,并且可能有大量的放射科医生,我无法在根视图中初始化所有内容,然后将其向下传递,我需要能够合并子视图状态。以表示文件系统导航为例,每个单选按钮都是您可以选择导航到的目录(有点像MacOS的“打开文件”对话框)。我已经通过您的第一条评论理解了这一点;)我正在考虑其他解决方案……但这不是“第一个问题”还有…这是第二个;)要清楚:每次父对象更改时都可以重新创建模型(并重置其状态),这不是我要调查的问题。我希望在更改与其关联的环境对象
实例时重新评估按钮的主体
(当刷新日期发生变化时会发生这种情况),但问题并不是“我如何才能使它工作”,而是“我做错了什么”.RadioListTest
会更新,并且每次刷新父视图时都会调用它的主体
。这也是RadioModel
的两个实例的原因。您可以通过方法init
和主体
上的断点来检查。但它的子视图不会更新,这就是导致错误的原因不添加显式id
会使SwiftUI识别单选按钮