在同一结构 SwiftUI 中将 @State 绑定到可选的 @Binding

Bind @State to optional @Binding in the same struct SwiftUI

我正在创建一个可能会或可能不会收到绑定的视图:


import SwiftUI

struct AssignmentEditMenu: View {
    
    @EnvironmentObject var planner: Planner
    @Environment(\.dismiss) var dismiss
    
    var isEditing // set to true if assignment is not nil
    var assignment: Binding<Assignment>?
        
    @State var newAssignment = assignment ?? Assignment()
    // if assignment is not nil, create a copy of it and set newAssignment equal to the copy
    // if assignment is nil, initialize a new struct and set newAssignment equal to it
    
    var body: some View {
        
        NavigationView {
            Form {
                nameSection
                dateSection
            }
            .navigationTitle(Text("New Assignment"))
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(isEditing ? "Add" : "Done") {
                        isEditing ? (assignment = newAssignment) : planner.addAssignment(newAssignment)
                        dismiss()
                    }
                }
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Cancel") {
                        dismiss()
                    }
                }
            }
        }
    }
    
    var nameSection: some View {
        Section {
            TextField("Name", text: $newAssignment.name)
            Picker("Course", selection: $newAssignment.course) {
                ForEach(planner.courses) { course in
                    Text("\(course.name)").tag(course)
                }
                
            }
        }
    }
    
    var dateSection: some View {
        Section {
            DatePicker(
                selection: $newAssignment.assignedDate,
                displayedComponents: [.date, .hourAndMinute]
            ) {
                Text("Assigned:")
                    .lineLimit(1)
                    .allowsTightening(true)
            }
            DatePicker(
                selection: $newAssignment.dueDate
            ) {
                Text("Due:")
                    .lineLimit(1)
                    .allowsTightening(true)
            }
        }
    }
}

我想做的是,如果在此处传递到 Assignment 的绑定,则视图处于编辑模式。 newAssignment 将被设置为与 assignment 绑定相同的值,但根本不引用它。它将收集更改并在完成后将 assignment 绑定设置为等于自身,从而保存更改。使用 newAssignment 的原因是如果用户取消(此视图将是 sheet)更改将被丢弃,因为 newAssignment 是一个 @State 变量。

当视图中没有传递 Assignment 绑定时,视图处于创建模式。 newAssignment 收集更改并通过 planner 添加到商店。

Assignment 实施:


struct Assignment: Identifiable, Equatable, Hashable  {
    var name: String
    var assignedDate: Date
    var dueDate: Date
    var course: Course
    var percentCompleted: Double
    let id: UUID
    
    init(
        name: String = "",
        assignedDate: Date = Date(),
        dueDate: Date = Calendar.current.nextDate(after: Date(), matching: .init(hour: 0, minute: 0), matchingPolicy: .strict)!,
        course: Course = Course()
    ) {
        self.name = name
        self.assignedDate = assignedDate
        self.dueDate = dueDate
        self.course = course
        self.id = UUID()
        self.percentCompleted = 0.0
    }
}

struct Course: Identifiable, Equatable, Hashable {
    var name: String
    let id: UUID
    
    init(_ name: String = "Course") {
        self.name = name
        self.id = UUID()
    }
}

添加自定义初始化。这样,也不需要 newAssignment var。

struct AssignmentEditMenu: View {
    
    @EnvironmentObject var planner: Planner
    @Environment(\.dismiss) var dismiss
    
    var isEditing // set to true if assignment is not nil

   var assignment: Binding<Assignment>
    
    init(a: Binding<Assignment> = .constant(Assignment())) {
        assignment = a 
    }

.....

}