简体   繁体   中英

SwiftUI: Binding on property of struct derived from environment object

I have two structs in my task manager app:

struct Task {
    var identifier: String
    var title: String
    var tags: [String] // Array of tag identifiers
}
struct Tag {
    var identifier: String
    var title: String
}

No, you're not necessarily doing something against best practices. I think in SwiftUI, the concepts of data model storage and manipulation quickly become more complex than, for example, what Apple tends to show in its demo code. With a real app, with a single source of truth, like you seem to be using, you're going to have to come up with some ways to bind the data to your views.

That might look like this, for example:

struct TaskView : View {
    var taskIdentifier: String // Passed from parent view
    
    @EnvironmentObject private var taskStore: TaskStore
    
    private var taskBinding : Binding<Task> {
        Binding {
            taskStore.tasks[taskIdentifier] ?? .init(identifier: "", title: "", tags: [])
        } set: {
            taskStore.tasks[taskIdentifier] = $0
        }
    }
    
    var body: some View {
        TextField("Task title", text: taskBinding.title)
    }
}

You are correct to model your data with value types and manage lifecycle and side-effects with a reference type. The bit you are missing is that Task doesn't implement the Identifiable<\/code> protocol which enables SwiftUI to keep track of the data in a List<\/code> or ForEach<\/code> . Implement that as follows:

struct Task: Identifiable {
    var id: String
    var title: String
    var tags: [String] // Array of tag identifiers
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM