英文:
Why does change in the model not reflect in child views?
问题
这段代码创建了一个包含两个SubItem结构的VStack,每个SubItem结构都包含一个名称和一个数字。当点击方框时,数字的值应该通过调用控制器的处理程序@Published var model增加1。
问题在于数字值的更改没有显示出来。
我初始化了每个视图以查看传递的值。似乎一直正常工作,直到ItemsDisplay:View。
但是似乎该视图的body没有被调用,因此ItemDisplay:View永远不会显示新值。
我不明白为什么当使用正确更改的项目调用init时,它的body不会被调用。
有任何想法吗?
当我点击box1时,会打印出以下内容:
tapped
updating: box1
newValue for item: box1 should be: 2
changing value to: 2
newValue of item: box1 is: 2
init of ItemsDisplay
box1 2
box10 10
英文:
struct ContentView: View {
@StateObject var cntrl=ContentViewController2()
var body: some View {
VStack {
ItemsDisplay(items: cntrl.model.items, handler: cntrl.updateItem)
}
}
}
struct ItemsDisplay:View {
let items:[SubItem]
let handler:(SubItem)->Void
init(items: [SubItem], handler: @escaping (SubItem) -> Void) {
self.items = items
self.handler = handler
print("init of ItemsDisplay")
for item in items {
print("\(item.id) \(item.value)")
}
}
var body: some View {
VStack {
ForEach(items, id: \.id) {item in
ItemDisplay(item: item, handler: handler)
}
}
}
}
struct ItemDisplay:View {
let item:SubItem
let handler:(SubItem)->Void
init(item: SubItem, handler: @escaping (SubItem) -> Void) {
self.item = item
self.handler = handler
print("init of ItemDisplay: \(item.value)")
}
var body: some View {
VStack {
Text("\(item.id)")
Text("\(item.value)")
}
.padding(.all)
.border(.black, width:5)
.onTapGesture {
print("tapped")
handler(item)
}
}
}
struct SubItem:Equatable {
static func == (lhs: SubItem, rhs: SubItem) -> Bool {
lhs.id == rhs.id
}
let id:String
var value:Int
mutating func changeValue(_ newval:Int) {
print("changing value to: \(newval)")
value=newval
}
}
struct ContentViewModel2 {
var items:[SubItem]
mutating func updateItem(_ item:SubItem) {
if let i=items.firstIndex(of: item) {
let newValue=item.value+1
print("newValue for item: \(item.id) should be: \(newValue)")
items[i].changeValue(newValue)
print("newValue of item: \(items[i].id) is: \(items[i].value)")
}
}
}
class ContentViewController2:ObservableObject {
@Published var model:ContentViewModel2
init() {
model=ContentViewModel2(items: [SubItem(id: "box1", value: 1), SubItem(id: "box10", value: 10)])
}
func updateItem(_ item:SubItem) {
if let i=model.items.firstIndex(of: item) {
print("updating: \(item.id)")
model.updateItem(item)
}
// objectWillChange.send()
}
}
The code above creates a VStack of 2 SubItem structs as a box with a name and a number. When the box is clicked, the value of the number displayed should increment by 1 by calling a handler of the controller that holds the "source of truth" in @Published var model.
The problem is that the change in value does not show.
I init each View to see what values are passed. It seems to work all the way down to ItemsDisplay:View.
But it seems that the body of this View is not called, thus the ItemDisplay:View never gets to display the new value.
I don't understand why when the init is called with items that have changed correctly, it's body is not called.
Any ideas?
When I click on the box1, this prints out:
tapped
updating: box1
newValue for item: box1 should be: 2
changing value to: 2
newValue of item: box1 is: 2
init of ItemsDisplay
box1 2
box10 10
答案1
得分: 0
这个
static func == (lhs: SubItem, rhs: SubItem) -> Bool {
lhs.id == rhs.id
}
是告诉 SwiftUI 仅在 id
改变时重新加载视图。
移除它。
保留 Equatable
的原始实现。
SwiftUI 依赖于 Equatable、Identifiable 和 Hashable。除非你有充分的理由,不要覆盖默认的实现。
英文:
This
static func == (lhs: SubItem, rhs: SubItem) -> Bool {
lhs.id == rhs.id
}
Is telling SwiftUI to only reload views when the id
changes.
Remove it.
Keep the original implementation of Equatable
SwiftUI is dependent on Equatable, Identifiable and Hashable. Don’t override default implementations unless you have a really good reason.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论