我在 SwiftUI 中遇到一个问题,我尝试使用 ForEach 循环来迭代结构数组 (v.columns) 并根据条件更新属性。这些结构具有 [Any] 类型的 expressionKeypathSegment 属性,我尝试使用自定义比较函数 (compareArrays) 来确定循环内按钮的背景颜色。
这是代码的简化版本:
ForEach(v.columns, id: \.index) { v2 in
if v2.isBtnStyle {
Button(action: {
expressionKeypathSegment = v2.expressionKeypathSegment
}) {
Text(v2.text)
.padding(EdgeInsets(top: 4, leading: 16, bottom: 4, trailing: 16))
.foregroundColor(.white)
.background(/*compareArrays(expressionKeypathSegment, v2.expressionKeypathSegment) ? Color.purple :*/ Color.blue)
.cornerRadius(8)
}
} else {
Text(v2.text)
}
}
当我用compareArrays 取消注释该行时,出现错误:“无法将类型‘[ExpressionColumn]’的值转换为预期的参数类型‘Binding’”。注释掉这一行可以解决问题,表明问题可能与compareArrays的使用有关。
这是compareArrays的实现:
func compareArrays<T: Equatable>(_ array1: [T], _ array2: [T]) -> Bool {
guard array1.count == array2.count else {
return false
}
for (element1, element2) in zip(array1, array2) {
guard type(of: element1) == type(of: element2) else {
return false
}
guard element1 == element2 else {
return false
}
}
return true
}
我怀疑这个问题可能与 ExpressionColumn 如何处理相等或泛型的使用有关。任何关于为什么会发生此错误以及我如何解决它的见解将不胜感激。谢谢!
您可以根据您的具体情况随意定制问题,并提供任何可能相关的其他详细信息。
你的问题是 Any 类型不符合 Equatable 协议,在我的例子中编译器对此非常清楚。 此外,您的代码不容易在其他人的机器上进行测试。仅仅复制它并将其粘贴到 XCode 中是不够的,我必须进行许多编辑才能使其工作,并找到一种重新编码代码结构的方法。 顺便说一句,我让它工作了,但正如我所说,我无法使用 Any,因为它不是 Equatable。这是我的代码版本:
struct ContentView: View {
@StateObject private var trialStruct = TrialStruct()
@State private var expressionKeypathSegment: [Int]?
var body: some View {
VStack {
ForEach($trialStruct.columns, id: \.id) { v2 in
if v2.isBtnStyle.wrappedValue {
Button(action: {
expressionKeypathSegment = v2.expressionKeypathSegment.wrappedValue
}) {
Text(v2.text.wrappedValue)
.padding(EdgeInsets(top: 4, leading: 16, bottom: 4, trailing: 16))
.foregroundColor(.white)
.background(compareArrays(expressionKeypathSegment ?? [0], v2.expressionKeypathSegment.wrappedValue) ? Color.purple : Color.blue)
.cornerRadius(8)
}
} else {
Text(v2.text.wrappedValue)
}
}
}
.onAppear {
trialStruct.columns = [
.init(index: 0, expressionKeypathSegment: ["1"], isBtnStyle: true, text: "Hello"),
.init(index: 1, expressionKeypathSegment: ["2"], isBtnStyle: false, text: "Hello"),
]
}
}
func compareArrays<T: Equatable>(_ array1: [T], _ array2: [T]) -> Bool {
guard array1.count == array2.count else {
return false
}
for (element1, element2) in zip(array1, array2) {
guard type(of: element1) == type(of: element2) else {
return false
}
guard element1 == element2 else {
return false
}
}
return true
}
}
class TrialStruct: ObservableObject {
@Published var columns = [Column]()
}
struct Column: Identifiable {
var id = UUID()
var index: Int
var expressionKeypathSegment: [Int]
var isBtnStyle: Bool
var text: String
init(id: UUID = UUID(), index: Int, expressionKeypathSegment: [Int], isBtnStyle: Bool, text: String) {
self.id = id
self.index = index
self.expressionKeypathSegment = expressionKeypathSegment
self.isBtnStyle = isBtnStyle
self.text = text
}
init(id: UUID = UUID(), index: Int, expressionKeypathSegment: [String], isBtnStyle: Bool, text: String) {
self.id = id
self.index = index
self.expressionKeypathSegment = expressionKeypathSegment.map({ Int($0) ?? 0 })
self.isBtnStyle = isBtnStyle
self.text = text
}
}
我使用了 String 而不是 Any,您可以使用最适合您需求的类型。 该代码似乎按预期工作。一旦我点击 isBtnStyle 为 true 的按钮,它就会变成紫色: