Sunday, November 8, 2026
HomeiOS Developmentios - Why does this SwiftUI Checklist require an additional objectWillChange.ship?

ios – Why does this SwiftUI Checklist require an additional objectWillChange.ship?

[ad_1]

Right here is an easy record view of “Matter” struct gadgets. The objective is to current an editor view when a row of the record is tapped. On this code, tapping a row is predicted to trigger the chosen matter to be saved as “tappedTopic” in an @State var and units a Boolean @State var that causes the EditorV to be introduced.

When the code as proven is run and a line is tapped, its matter title prints correctly within the Print assertion within the Button motion, however then the app crashes as a result of self.tappedTopic! finds tappedTopic to be nil within the EditTopicV(…) line.

If the road “tlVM.objectWillChange.ship()” is uncommented, the code runs superb. Why is that this wanted?

And a second puzzle: within the case the place the code runs superb, with the objectWillChange.ship() uncommented, a print assertion within the EditTopicV init() exhibits that it runs twice. Why?

Any assist could be vastly appreciated. I’m utilizing Xcode 13.2.1 and my deployment goal is ready to iOS 15.1.

Matter.swift:

struct Matter: Identifiable {
    var title: String = "Default"
    var iconName: String = "circle"
    var id: String { title }
}

TopicListV.swift:

struct TopicListV: View {
    @ObservedObject var tlVM: TopicListVM

    @State var tappedTopic: Matter? = nil
    @State var doEditTappedTopic = false
    
    var physique: some View {
        VStack(alignment: .main) {
            Checklist {
                ForEach(tlVM.matters) { matter in
                    Button(motion: {
                        tappedTopic = matter
                        
                        // why is the next line wanted?
                        tlVM.objectWillChange.ship()
                        
                        doEditTappedTopic = true
                        print("Tapped matter = (tappedTopic!.title)")
                    }) {
                        Label(matter.title, systemImage: matter.iconName)
                            .padding(10)
                    }
                }
            }
            
            Spacer()
        }
        .sheet(isPresented: $doEditTappedTopic) {
            EditTopicV(tlVM: tlVM, originalTopic: self.tappedTopic!)
        }
    }
}

EditTopicV.swift (Editor View):

struct EditTopicV: View {
    @ObservedObject var tlVM: TopicListVM
    @Atmosphere(.presentationMode) var presentationMode
    let originalTopic: Matter
    
    @State non-public var editTopic: Matter
    @State non-public var ic = "circle"
    let iconList = ["circle", "leaf", "photo"]
    
    init(tlVM: TopicListVM, originalTopic: Matter) {
        print("DBG: EditTopicV: originalTopic = (originalTopic)")
        self.tlVM = tlVM
        self.originalTopic = originalTopic
        self._editTopic = .init(initialValue: originalTopic)
    }
    
    var physique: some View {
        VStack(alignment: .main) {
            HStack {
                Button("Cancel") {
                    presentationMode.wrappedValue.dismiss()
                }
                Spacer()
                Button("Save") {
                    editTopic.iconName = editTopic.iconName.lowercased()
                    tlVM.change(matter: originalTopic, to: editTopic)
                    presentationMode.wrappedValue.dismiss()
                }
            }
            
            HStack {
                Textual content("Identify:")
                TextField("title", textual content: $editTopic.title)
                Spacer()
            }
            Picker("Coloration Theme", choice: $editTopic.iconName) {
                ForEach(iconList, id: .self) { icon in
                    Textual content(icon).tag(icon)
                }
            }
            .pickerStyle(.segmented)

            Spacer()
        }
        .padding()
    }
}

TopicListVM.swift (Observable Object View Mannequin):

class TopicListVM: ObservableObject {
    @Revealed var matters = [Topic]()
    
    func append(matter: Matter) {
        matters.append(matter)
    }
    
    func change(matter: Matter, to newTopic: Matter) {
        if let index = matters.firstIndex(the place: { $0.title == matter.title }) {
            matters[index] = newTopic
        }
    }
    
    static func ex1() -> TopicListVM {
        let tvm = TopicListVM()
        tvm.append(matter: Matter(title: "leaves", iconName: "leaf"))
        tvm.append(matter: Matter(title: "images", iconName: "picture"))
        tvm.append(matter: Matter(title: "shapes", iconName: "circle"))
        return tvm
    }

}

Here is what the record appears to be like like:

Topic List

[ad_2]

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments