SwiftUI:扩展数组以获得数组实例的绑定(bind)

标签 swift swiftui

我想延长 Array<T>基本上返回 Binding<T> . 这样做的目的是有一种方便的方法来创建 BindingDetailView这是从 NavigationLink 调用的的 List .

这是我到目前为止得到的:

extension Array where Element: Identifiable {
    mutating func getBinding(of instance: Element) -> Binding<Element> {
        if let index = self.firstIndex(where: { $0.id == instance.id }) {
            return Binding(
                get: { self[index] }, //error
                set: { self[index] = $0}) //error
        } else {
            fatalError() //implement error handling here
        }
    }
}

我收到错误 Escaping closure captures mutating 'self' parameter在指定地点。我该如何解决这个问题?

长话短说

以下是我想使用此扩展程序的方式:

class ViewModel: ObservableObject {
    @Published var items: [Item]
    
    init(with items: [Item] = [Item]()) {
        self.items = items
    }
}

struct Item: Identifiable, Hashable {
    let id: UUID
    var title: String
    
    static var sampleItems: [Item] {
        var items = [Item]()
        for i in 0..<10 {
            items.append(Item(id: UUID(), title: "item \(i)"))
        }
        return items
    }
}

struct ContentView: View {
    @StateObject private var viewModel = ViewModel(with: Item.sampleItems)
    
    var body: some View {
        NavigationView {
            List {
                Section {
                    ForEach(viewModel.items) { item in
                        //MARK: Using Array.getBinding(of:) here
                        NavigationLink(item.title, destination: DetailView(item: viewModel.items.getBinding(of: item)))
                    }
                }
            }
        }
    }
}

struct DetailView: View {
    @Binding var item: Item
    
    var body: some View {
        TextField("Item Title", text: $item.title)
    }
}

最佳答案

将扩展名更改为:

extension Binding {
    func getBinding<T>(of instance: T) -> Binding<T>
    where Value == [T], T: Identifiable {
        if let index = self.wrappedValue.firstIndex(where: { $0.id == instance.id }) {
            return .init(
                get: { self.wrappedValue[index] }, //error
                set: { self.wrappedValue[index] = $0 }) //error
        } else {
            fatalError() //implement error handling here
        }
    }
}

现在代替 DetailView(item: viewModel.items.getBinding(of: item))DetailView(item: $viewModel.items.getBinding(of: item)) (注意 $)

编辑,奖励:

我有一份奖励送给你,希望你会喜欢。这将使过程更好,代码更清晰。请注意,它与您当前的代码在性能方面的差异为 0。
添加此扩展以开始:

extension Binding {
    subscript<T>(_ index: Int) -> Binding<T> where Value == [T] {
        .init(get: {
            self.wrappedValue[index]
        },
        set: {
            self.wrappedValue[index] = $0
        })
    }
}

并将您的 ForEach 更改为:

ForEach(viewModel.items.indices) { index in
    let item = viewModel.items[index]
    NavigationLink(item.title, destination: DetailView(item: $viewModel.items[index]))
}

希望你喜欢:)

关于SwiftUI:扩展数组以获得数组实例的绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67059931/

相关文章:

swift - NSComboBox 未在下拉列表中显示当前选定的值

inheritance - Swift——要求实现协议(protocol)的类是某个类的子类

ios - 从 swiftUI 中的另一个 View 中关闭模态视图

swiftui - 缩小选择器以适应内容而不是更大

ios - SwiftUI如何调整不同的屏幕尺寸

SwiftUI ForEach 获取二维数组中的元素和索引

ios - UITableview Cell 动画只播放一次

ios - UITableView deleteRows 未更新 IndexPaths 导致崩溃索引超出范围

ios - 如何使用 Swift 制作 pod

ios - 为什么 SwiftUI 教程中没有显示 Image 对象?