Xcode 11 beta 5:“'subscript(_:)' 已弃用:有关迁移路径,请参阅发行说明。”

Xcode 11 beta 5: " 'subscript(_:)' is deprecated: See Release Notes for migration path. "

我想使用如下代码:

import Foundation
import Combine
import SwiftUI

final class DataStore: ObservableObject {
    @Published var bools: [Bool] = [true, false]
}

struct ContentView: View {
    @EnvironmentObject var dataStore: DataStore
    var body: some View {
        HStack {
            Spacer()
            Toggle(isOn: $dataStore.bools[0]) {
                Text(dataStore.bools[0] ? "On" : "Off")
            }
            Spacer()
            Toggle(isOn: $dataStore.bools[1]) {
                Text(dataStore.bools[1] ? "On" : "Off")
            }
            Spacer()
        }
    }
}

(其实这段代码没什么用,只是想把数组的一个元素作为绑定传递给子视图。)

在 Xcode beta 2 中这行得通,但自 beta 5 以来,我在 "Toggle" 行都收到以下警告:

'subscript(_:)' is deprecated: See Release Notes for migration path. And the app crashes when I try to launch it.

确实,我已经阅读了release notes,我认为这个问题与"the Binding structure’s conditional conformance to the Collection protocol is removed"有关。
问题是我不明白如何将他们提供的示例代码与我想使用的代码一起使用。有人可以帮我吗?

Xcode 11,测试版 6 更新:

好消息!正如我所怀疑的那样,在 beta 6 中,BindingMutableCollection 的一致性已被其他内容所取代。它不再遵循 MutableCollection,而是让您通过 @dynamicMemberLookup 访问元素。结果是您现在可以继续 dataStore.bools[0] 而不再收到警告!

Xcode 11,测试版 5(旧答案)

如果你想摆脱弃用,你可以使用下面的代码:

我用类似的东西来回答一个稍微不同的问题。在另一种情况下,它是一个 Binding,而不是一个 ObservableObject(这就是我不将其标记为重复的原因)。但是,基础是相同的:

我觉得在下一个测试版中,有些东西会再次发生变化,因为发行说明中存在一些矛盾。

final class DataStore: ObservableObject {
    @Published var bools: [Bool] = [true, false]

    func element(idx: Int) -> Binding<Bool> {
        return Binding<Bool>(get: { () -> Bool in
            return self.bools[idx]
        }) {
            self.bools[idx] = [=10=]
        }
    }
}

struct ContentView: View {
    @EnvironmentObject var dataStore: DataStore
    var body: some View {
        HStack {
            Spacer()
            Toggle(isOn: dataStore.element(idx: 0)) {
                Text(dataStore.bools[0] ? "On" : "Off")
            }
            Spacer()
            Toggle(isOn: dataStore.element(idx: 1)) {
                Text(dataStore.bools[1] ? "On" : "Off")
            }
            Spacer()
        }
    }
}

或者,您可以使用其他问题的解决方案,其中涉及扩展绑定:

final class DataStore: ObservableObject {
    @Published var bools: [Bool] = [true, false]
}

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
        })
    }
}

struct ContentView: View {
    @EnvironmentObject var dataStore: DataStore
    var body: some View {
        HStack {
            Spacer()
            Toggle(isOn: $dataStore.bools.element(0)) {
                Text(dataStore.bools[0] ? "On" : "Off")
            }
            Spacer()
            Toggle(isOn: $dataStore.bools.element(1)) {
                Text(dataStore.bools[1] ? "On" : "Off")
            }
            Spacer()
        }
    }
}

基于kontiki的非常有用的回答,我做了以下扩展,这样你就可以像以前一样使用下标了:

extension Binding where Value: MutableCollection, Value.Index == Int {
    public subscript(position: Value.Index) -> Binding<Value.Element> {
        Binding<Value.Element>(get: {
            self.wrappedValue[position]
        }, set: {
            self.wrappedValue[position] = [=10=]
        })
    }
}

理论上,如果需要,您可以对 subscript(bounds:) 执行相同的操作。