Swift 具有不同存储属性的初始值设定项

Swift 具有不同存储属性的初始值设定项,swift,swiftui,Swift,Swiftui,我在下面的视图中向需要选择的项目传递绑定 struct SelectionListView<Data>: View where Data: RandomAccessCollection, Data.Element: Identifiable, Data.Element: Named { private let data: Data @Binding private var isPresented: Bool @Binding private var sele

我在下面的视图中向需要选择的项目传递绑定

struct SelectionListView<Data>: View where Data: RandomAccessCollection, Data.Element: Identifiable, Data.Element: Named {

    private let data: Data
    @Binding private var isPresented: Bool
    @Binding private var selectedElement: Data.Element

    init(
        data: Data,
        selectedElement: Binding<Data.Element>,
        isPresented: Binding<Bool>
    ) {
        self.data = data
        _selectedElement = selectedElement
        _isPresented = isPresented
    }
    
    var body: some View {
        VStack {
            ForEach(data) { element in
                Button(element.name) {
                    selectedElement = element
                    isPresented.toggle()
                }
                .foregroundColor(
                    selectedElement.id == item.id
                        ? .black
                        : .white
                )
            }
        }
    }
}
struct SelectionListView:查看其中的数据:RandomAccessCollection,数据。元素:可识别,数据。元素:命名{
私人出租数据:数据
@绑定私有变量已呈现:Bool
@绑定私有变量selectedElement:Data.Element
初始化(
数据:数据,
selectedElement:绑定,
显示:绑定
) {
self.data=数据
_selectedElement=selectedElement
_isPresented=isPresented
}
var body:一些观点{
VStack{
ForEach(数据){元素在
按钮(element.name){
selectedElement=元素
isPresented.toggle()
}
.前底色(
selectedElement.id==item.id
黑色
怀特先生
)
}
}
}
}
我需要一个稍微不同的视图初始值设定项,在这里我只能传递元素ID,而不是整个元素。我很难实现这个解决方案。更清楚地说,如果我能有第二个初始值设定项,那就太好了:

init(
    data: Data,
    selectedId: Binding<Data.Element.ID>,
    isPresented: Binding<Bool>
)
init(
数据:数据,
选择edid:Binding,
显示:绑定
)

这是一个工作版本。我决定将
元素
id
存储在它们自己的枚举案例中。我将视图分开,只是为了更容易理解我所做的

工作代码:

struct SelectionListView<Data>: View where Data: RandomAccessCollection, Data.Element: Identifiable, Data.Element: Named {
    
    enum Selected {
        case element(Binding<Data.Element>)
        case id(Binding<Data.Element.ID>)
    }
    
    @Binding private var isPresented: Bool
    private let data: Data
    private let selected: Selected
    
    init(
        data: Data,
        selectedElement: Binding<Data.Element>,
        isPresented: Binding<Bool>
    ) {
        self.data = data
        selected = .element(selectedElement)
        _isPresented = isPresented
    }
    
    init(
        data: Data,
        selectedId: Binding<Data.Element.ID>,
        isPresented: Binding<Bool>
    ) {
        self.data = data
        selected = .id(selectedId)
        _isPresented = isPresented
    }
    
    var body: some View {
        SelectionListItem(data: data) { dataElement in
            switch selected {
            case .element(let element):
                element.wrappedValue = dataElement
                print("Selected element:", element.wrappedValue)
            case .id(let id):
                id.wrappedValue = dataElement.id
                print("Selected element ID:", id.wrappedValue)
            }
            
            isPresented.toggle()
        }
    }
}


struct SelectionListItem<Data>: View where Data: RandomAccessCollection, Data.Element: Identifiable, Data.Element: Named {
    let data: Data
    let action: (Data.Element) -> Void
    
    var body: some View {
        VStack {
            ForEach(data) { element in
                Button(element.name) {
                    action(element)
                }
                .foregroundColor(
                    .red  // Temporary because I don't know what `item.id` is

//                    selectedElement.id == item.id
//                        ? .black
//                        : .white
                )
            }
        }
    }
}

我真的不确定你想要实现什么。感觉有些不对劲:)但不管怎样,这里有一个代码变体可以满足您的需要:

struct SelectionListView<Data>: View where Data: RandomAccessCollection, Data.Element: Identifiable, Data.Element: Named {

    private let data: Data
    @Binding private var isPresented: Bool
    @Binding private var selectedElement: Data.Element
    @Binding private var selectedId: Data.Element.ID
    
    init(
        data: Data,
        selectedElement: Binding<Data.Element>,
        isPresented: Binding<Bool>
    ) {
        self.data = data
        _selectedElement = selectedElement
        _selectedId = .constant(selectedElement.wrappedValue.id)
        _isPresented = isPresented
    }
    
    init(
        data: Data,
        selectedId: Binding<Data.Element.ID>,
        isPresented: Binding<Bool>
    ) {
        self.data = data
        _selectedElement = .constant(data.first(where: { $0.id == selectedId.wrappedValue })!)
        _selectedId = selectedId
        _isPresented = isPresented
    }
    
    var body: some View {
        VStack {
            ForEach(data) { element in
                Button(element.name) {
                    selectedElement = element
                    selectedId = element.id
                    isPresented.toggle()
                }
                .foregroundColor(
                    selectedElement.id == element.id
                        ? .black
                        : .gray
                )
            }
        }
    }
}
struct SelectionListView:查看其中的数据:RandomAccessCollection,数据。元素:可识别,数据。元素:命名{
私人出租数据:数据
@绑定私有变量已呈现:Bool
@绑定私有变量selectedElement:Data.Element
@绑定私有变量selectedId:Data.Element.ID
初始化(
数据:数据,
selectedElement:绑定,
显示:绑定
) {
self.data=数据
_selectedElement=selectedElement
_selectedId=.constant(selectedElement.wrappedValue.id)
_isPresented=isPresented
}
初始化(
数据:数据,
选择edid:Binding,
显示:绑定
) {
self.data=数据
_selectedElement=.constant(data.first(其中:{$0.id==selectedId.wrappedValue})!)
_selectedId=selectedId
_isPresented=isPresented
}
var body:一些观点{
VStack{
ForEach(数据){元素在
按钮(element.name){
selectedElement=元素
selectedId=element.id
isPresented.toggle()
}
.前底色(
selectedElement.id==element.id
黑色
格雷先生
)
}
}
}
}

您遇到了什么错误?类似于“无法分配给属性:'id'在尝试创建绑定id时是一个'let'常量”@George_E是的,但除此之外,我真的很想实现这两个初始化。如果您只传递id,您希望
selectedElement=element
如何工作?@George_E我最好解释一下自己。如果我可以有两个不同的绑定,
selectedElement
selectedId
,并且有两个不同的初始值设定项来管理其中一个,那就太好了。解决方案是重写相同的视图以使用ids,但这会导致大量代码重复。因此,对于这种情况,您会选择
selectedElement.id=element.id
?这是一个简单而优雅的解决方案。我很感激,谢谢。:)
struct SelectionListView<Data>: View where Data: RandomAccessCollection, Data.Element: Identifiable, Data.Element: Named {

    private let data: Data
    @Binding private var isPresented: Bool
    @Binding private var selectedElement: Data.Element
    @Binding private var selectedId: Data.Element.ID
    
    init(
        data: Data,
        selectedElement: Binding<Data.Element>,
        isPresented: Binding<Bool>
    ) {
        self.data = data
        _selectedElement = selectedElement
        _selectedId = .constant(selectedElement.wrappedValue.id)
        _isPresented = isPresented
    }
    
    init(
        data: Data,
        selectedId: Binding<Data.Element.ID>,
        isPresented: Binding<Bool>
    ) {
        self.data = data
        _selectedElement = .constant(data.first(where: { $0.id == selectedId.wrappedValue })!)
        _selectedId = selectedId
        _isPresented = isPresented
    }
    
    var body: some View {
        VStack {
            ForEach(data) { element in
                Button(element.name) {
                    selectedElement = element
                    selectedId = element.id
                    isPresented.toggle()
                }
                .foregroundColor(
                    selectedElement.id == element.id
                        ? .black
                        : .gray
                )
            }
        }
    }
}