【问题标题】:Crash when array is empty in iOS 14.3iOS 14.3 中数组为空时崩溃
【发布时间】:2021-01-10 13:37:03
【问题描述】:

我试图在数组为空时显示一些占位符数据。这在 iOS 13.7 中有效,但在 iOS 14.3 中发生了一些变化,所以当最后一个项目被删除时,你会遇到这个崩溃:

致命错误:索引超出范围:文件 Swift/ContiguousArrayBuffer.swift,第 444 行

如果我注释掉 testStore.data.isEmpty 并返回 Form 我不会崩溃。

如何在 iOS 14.3 中数组为空时显示占位符?

struct Test: Identifiable {
    var text: String
    var id: String { text }
}

extension Test {
    final class Store: ObservableObject {
        @Published var data = [Test(text: "Hi"), Test(text: "Bye")]
    }
}

struct TestList: View {
    
    @EnvironmentObject var testStore: Test.Store
    
    var body: some View {
        Group {
            if testStore.data.isEmpty {
                Text("Empty")
            } else {
                Form {
                    ForEach(testStore.data.indices, id: \.self) { index in
                        TestRow(test: $testStore.data[index], deleteHandler: { testStore.data.remove(at: index) })
                    }
                }
            }
        }
    }
}

struct TestRow: View {
    
    @Binding var test: Test
    let deleteHandler: (() -> ())
    
    var body: some View {
        HStack {
            Text(test.text)
                .font(.headline)
            Spacer()
            Button(action: deleteHandler, label: Image(systemName: "trash"))
        }
    }
}

【问题讨论】:

标签: ios arrays swift list swiftui


【解决方案1】:

您可以使用建议的扩展here

struct Safe<T: RandomAccessCollection & MutableCollection, C: View>: View {
    typealias BoundElement = Binding<T.Element>
    private let binding: BoundElement
    private let content: (BoundElement) -> C

    init(_ binding: Binding<T>, index: T.Index, @ViewBuilder content: @escaping (BoundElement) -> C) {
        self.content = content
        self.binding = .init(get: { binding.wrappedValue[index] },
                             set: { binding.wrappedValue[index] = $0 })
    }

    var body: some View {
        content(binding)
    }
}

然后,如果您还想保留ForEach 而不是List,您可以这样做:

struct TestList: View {
    @EnvironmentObject var testStore: Test.Store

    var body: some View {
        Group {
            if testStore.data.isEmpty {
                Text("Empty")
            } else {
                Form {
                    ForEach(testStore.data.indices, id: \.self) { index in
                        Safe($testStore.data, index: index) { binding in
                            TestRow(test: binding, deleteHandler: { testStore.data.remove(at: index) })
                        }
                    }
                }
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 2015-12-30
    • 1970-01-01
    • 2014-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多