Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding an element of an array of an ObservableObject : 'subscript(_:)' is deprecated

I'm using an ObservableObject 'DataStore', which contains an array ('exampleList') of objects ('exampleObject').

@Published exampleList = [exampleObject]()

I'm calling the DataStore via @EnvironmentObject ('dataStore').

@EnvironmentObject var dataStore = DataStore()

Then I iterate the list with

ForEach(0..<dataStore.exampleList.count) { index in ....

To bind element of item to a detail view, I'm doing like this:

DetailView(itemBinding: $dataStore.exampleList[index])

Until Xcode11 beta 4, it worked perfectly. Since XCode11 beta 5, it still works but Xcode gives me this alert:

'subscript(_:)' is deprecated: See Release Notes for a migration path

I tried with simpler stuff, with a simple @State var containing an array of strings, and it's the same issue: when calling an element of this array, and trying to use the value into a TextField:

TextField("test", text: $test[0])

I get the same alert.

I don't understand how to fix it. Does that mean that we no longer can bind values inside an array? Then, how can we iterate an array and bind a specific item?

This is my first question on Stack Overflow, I apologize if my question is clumsy... Thanks a lot for your answers, I'm using Stack Overflow for years, it's amazing, I always find existing and helpful answers, but it is the first time I can't find any, that's why I'm asking.

like image 912
hasselfred Avatar asked Aug 02 '19 10:08

hasselfred


1 Answers

Xcode 11, beta 6 UPDATE:

Good news! Just as I suspected, in beta 6, the Binding conformance to MutableCollection has been been replaced with something else. Instead of conforming to MutableCollection, it now let your access the elements via @dynamicMemberLookup. The result is you now can keep doing $text[3] and no longer get a warning! It seems this question can be closed now.

Xcode 11, beta 5. Old answer:

I finally got some time to investigate this a little. As I mentioned in the comments, I think it would be wise to wait until the Collection conformance is completely removed (or replaced with something else). But just to satisfy our curiosity, I have created an extension on Binding, that I think does what the current Collection conformance does. The only difference is that, instead of accessing through a subscript, I implemented a function called element(_ idx: Int) to get a Binding<T> to the element.

If one day the conformance is completely removed, I may change the implementation, and conform to Collection myself. I cannot do it now, because it would conflict with the existent (and deprecated) implementation. For the time being, I think this demonstrate how to handle the warnings if you absolutely want to get rid of them.

Just to be clear. I am not using this code. As long as I can still access the elements through the subscript, I will still do it and ignore the warnings. This is just for academic purposes.

The extension is:

extension Binding where Value: MutableCollection, Value.Index == Int {
    func element(_ idx: Int) -> Binding<Value.Element> {
        return Binding<Value.Element>(
            get: {
                return self.wrappedValue[idx]
        }, set: { (value: Value.Element) -> () in
            self.wrappedValue[idx] = value
        })
    }
}

And it can be used like this:

struct MainView: View {
    @Binding var text: [String]

    var body: some View {
        TextField("", text: $text.element(0))
        TextField("", text: $text.element(1))
        TextField("", text: $text.element(2))
    }
}
like image 141
kontiki Avatar answered Sep 20 '22 22:09

kontiki