'How to convert Binding array value to Binding<[type]> instead of [Binding<type>] in Swift/SwiftUI

I have trouble with getting Binding values in correct format out of dataModel.

The XCode error I am getting is "Cannot convert value of type '[Binding<String?>]' to expected argument type 'Binding<[String]>'"

public final class RoomSelectionDataModel: ObservableObject {
    @Published var roomsList: [Room]
    @Published var selectedRoom: String?

}
public struct RoomSelectionView: View {
    @StateObject var dataModel: RoomSelectionDataModel
    public var body: some View {
        let bindingArray = $dataModel.roomsList.compactMap { $0.name } // here the format is '[Binding<String?>]' instead of 'Binding<[String]>'
        SelectionList(listElements: bindingArray,
                      backgroundColor: Color(red: 0.94, green: 0.94, blue: 0.94), // color to be removed
                      selectedElement: $dataModel.selectedRoom)
    }
    
    public init(dataModel: RoomSelectionDataModel) {
        self._dataModel = StateObject(wrappedValue: dataModel)
        
    }
}
public struct SelectionList: View {
    
    let backgroundColor: Color
    @Binding var listElements: [String]
    @Binding var selectedElement: String?
    
    public init(listElements: Binding<[String]>, backgroundColor: Color, selectedElement: Binding<String?>) {
        self._listElements = listElements
        self.backgroundColor = backgroundColor
        self._selectedElement = selectedElement
    }
}
 public class Room: NSObject, Codable {
    public var name: String?
}

The models are simplified here, to only have the relevant information.



Solution 1:[1]

Lets try explicitly creating the binding array as it seems you wish to:

        let bindingArray = Binding<[String]>(
            get: { dataModel.roomsList.compactMap { $0.name } },
            set: { newValue in
                let rooms = dataModel.roomsList.filter { $0.name != nil }
                rooms.enumerated().forEach { numberedPair in
                    numberedPair.element.name = newValue[numberedPair.offset]
                }
            })

The get side of the binding is pretty straightforward. When you do the put side, things get a little more complicated. What my code does is assumes that the rooms are in the same order, that all the rooms which had names last time still have names, and that you're going to assign the names into the rooms that have them in their ordinal positions based on the new array.

All in all it's not clear why you want a Binding on the array because the put operation of [String] doesn't really match the model here.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Scott Thompson