Ios 符合SwiftUI中RandomAccessCollection时下标索引超出范围

Ios 符合SwiftUI中RandomAccessCollection时下标索引超出范围,ios,arrays,swift,swiftui,Ios,Arrays,Swift,Swiftui,我创建了一个类,并将其确认为observeObject以及RandomAccessCollection将该类视为数组的自定义实现,但我不需要它是一个结构。我需要它成为一门课 我试图通过调用名为append的自定义函数将一个项添加到类的内容中,这很好,但是当我要删除时,由于某种原因,它在subscript处崩溃,我试图跟踪它,似乎每次我删除它时,它都会循环通过包括已删除项在内的所有内容,然后崩溃。所以我不确定到底发生了什么。这是一段代码,带有可复制的代码(只需复制并粘贴即可) 如果我将代码更改为s

我创建了一个类,并将其确认为
observeObject
以及
RandomAccessCollection
将该类视为数组的自定义实现,但我不需要它是一个结构。我需要它成为一门课

我试图通过调用名为
append
的自定义函数将一个项添加到类的内容中,这很好,但是当我要删除时,由于某种原因,它在
subscript
处崩溃,我试图跟踪它,似乎每次我删除它时,它都会循环通过包括已删除项在内的所有内容,然后崩溃。所以我不确定到底发生了什么。这是一段代码,带有可复制的代码(只需复制并粘贴即可)

如果我将代码更改为struct,它将100%正常工作,但我需要它作为一个类

测试。swift

import Foundation

public class Test<Element : Hashable>: ObservableObject{
    @Published fileprivate var contents:[Element] = []
    
    public var count:Int {
        return self.contents.count
    }
    
    init() {
        
    }
}

public extension Test {
    func append(_ newElement: Element) {
        self.contents.append(newElement)
    }
    
    func remove(_ at: Int) {
        self.contents.remove(at: at)
    }
}

extension Test : Collection, RandomAccessCollection {
    public typealias Index = Int
    public typealias Indices = CountableRange<Int>
    
    public var startIndex: Int {
        return self.contents.startIndex
    }
    
    public var endIndex: Int {
        return self.contents.endIndex
    }
    
    public subscript(position: Int) -> Element {
        get {
            return self.contents[position] // Crash occurs here after trying to remove
        }
    }
    public func index(after i: Int) -> Int {
        return self.contents.index(after: i)
    }
    
    public func index(before i: Int) -> Int {
        return self.contents.index(before: i)
    }
}
import SwiftUI

struct ContentView: View {
    @ObservedObject var test: Test<String> = Test<String>()
    @State var input: String = ""
    
    var body: some View {
        VStack {
            HStack {
                TextField("New Item", text: self.$input)
                
                Button("Add", action: {
                    if(!self.input.isEmpty) {
                        self.test.append(self.input)
                    }
                })
            }
            
            Button("Remove", action: {
                self.test.remove(0)
            }).disabled(self.test.count <= 0)
            
            List {
                ForEach(self.test, id:\.self) { n in
                    Text(n)
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
<代码>导入基础 公共类测试:ObservieObject{ @已发布的fileprivate变量内容:[Element]=[] 公共变量计数:Int{ 返回self.contents.count } init(){ } } 公共扩展测试{ func append(uElement:Element){ self.contents.append(新元素) } func remove(u:Int){ self.contents.remove(at:at) } } 扩展测试:集合,随机访问集合{ 公共类型别名索引=Int 公共类型别名索引=可数范围 公共变量startIndex:Int{ 返回self.contents.startIndex } 公共变量endIndex:Int{ 返回self.contents.endIndex } 公共下标(位置:Int)->元素{ 得到{ return self.contents[position]//尝试删除后此处发生崩溃 } } 公共函数索引(在i:Int之后)->Int{ 返回self.contents.index(在:i之后) } 公共函数索引(在i:Int之前)->Int{ 返回self.contents.index(在:i之前) } } ContentView.swift

import Foundation

public class Test<Element : Hashable>: ObservableObject{
    @Published fileprivate var contents:[Element] = []
    
    public var count:Int {
        return self.contents.count
    }
    
    init() {
        
    }
}

public extension Test {
    func append(_ newElement: Element) {
        self.contents.append(newElement)
    }
    
    func remove(_ at: Int) {
        self.contents.remove(at: at)
    }
}

extension Test : Collection, RandomAccessCollection {
    public typealias Index = Int
    public typealias Indices = CountableRange<Int>
    
    public var startIndex: Int {
        return self.contents.startIndex
    }
    
    public var endIndex: Int {
        return self.contents.endIndex
    }
    
    public subscript(position: Int) -> Element {
        get {
            return self.contents[position] // Crash occurs here after trying to remove
        }
    }
    public func index(after i: Int) -> Int {
        return self.contents.index(after: i)
    }
    
    public func index(before i: Int) -> Int {
        return self.contents.index(before: i)
    }
}
import SwiftUI

struct ContentView: View {
    @ObservedObject var test: Test<String> = Test<String>()
    @State var input: String = ""
    
    var body: some View {
        VStack {
            HStack {
                TextField("New Item", text: self.$input)
                
                Button("Add", action: {
                    if(!self.input.isEmpty) {
                        self.test.append(self.input)
                    }
                })
            }
            
            Button("Remove", action: {
                self.test.remove(0)
            }).disabled(self.test.count <= 0)
            
            List {
                ForEach(self.test, id:\.self) { n in
                    Text(n)
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
导入快捷界面
结构ContentView:View{
@ObservedObject变量测试:测试=测试()
@状态变量输入:String=“”
var body:一些观点{
VStack{
HStack{
文本字段(“新项目”,文本:self.$input)
按钮(“添加”,操作:{
如果(!self.input.isEmpty){
self.test.append(self.input)
}
})
}
按钮(“移除”),操作:{
自测试。删除(0)

}).disabled(self.test.count
ForEach
未看到数据中的更改,因为
self.test
是一个参考

这里是可能的解决方法(仍然有测试的
内容
private)

    List {
        ForEach(Array(self.test), id:\.self) { n in
            Text(n)
        }
    }

由于超出了数组边界,因此可以将集合的返回值设置为可选值,也可以在init中指定一个默认值,以便在数组为空时返回

@ObservedObject var test: Test<String> = Test<String>(emptyValue: "")

public class Test<Element : Hashable>: ObservableObject{
    private let empty: Element
    @Published fileprivate var contents:[Element] = []

    public var count:Int {
        return self.contents.count
    }
    init(emptyValue: Element) {
        empty = emptyValue
    }
}

extension Test {
    func append(_ newElement: Element) {
        self.contents.append(newElement)
    }

    func remove(_ at: Int) {
        self.contents.remove(at: at)
    }
}

extension Test : Collection, RandomAccessCollection {
    public typealias Index = Int
    public typealias Indices = CountableRange<Int>

    public var startIndex: Int {
        return self.contents.startIndex
    }

    public var endIndex: Int {
        return self.contents.endIndex
    }

    public subscript(position: Int) -> Element {
        get {
            position < self.contents.count ? self.contents[position] : empty
        }
    }
    public func index(after i: Int) -> Int {
        return self.contents.index(after: i)
    }

    public func index(before i: Int) -> Int {
        return self.contents.index(before: i)
    }
}
@ObservedObject变量测试:测试=测试(emptyValue:)
公共类测试:ObservieObject{
私有let空:元素
@已发布的fileprivate变量内容:[Element]=[]
公共变量计数:Int{
返回self.contents.count
}
init(emptyValue:Element){
empty=emptyValue
}
}
延伸试验{
func append(uElement:Element){
self.contents.append(新元素)
}
func remove(u:Int){
self.contents.remove(at:at)
}
}
扩展测试:集合,随机访问集合{
公共类型别名索引=Int
公共类型别名索引=可数范围
公共变量startIndex:Int{
返回self.contents.startIndex
}
公共变量endIndex:Int{
返回self.contents.endIndex
}
公共下标(位置:Int)->元素{
得到{
位置Int{
返回self.contents.index(在:i之后)
}
公共函数索引(在i:Int之前)->Int{
返回self.contents.index(在:i之前)
}
}

我可以看到列表随着代码的添加而改变,也没有变化;但是,即使在您提议的更改之后,当我尝试删除时,
索引仍然超出范围。
感谢您的回复。这确实解决了问题,但我理解这是一个解决方法。我还理解,
ForEach
在g更改,但我无法理解的是,为什么在我执行
添加
而不是
删除
时,它能够看到更改?您是否认为在此时没有黑客攻击就无法做到这一点?或者我现在要求的对类来说是不可能的?因为上面的代码对
struct
但我知道struct是值类型。谢谢您的帮助。