自定义协议不支持 SwiftUI 中的 Identifiable

问题描述 投票:0回答:1

我定义了一个

CustomProtocol
,它需要一个唯一的标识符。我还创建了一个实现此协议的
CustomModel
。尽管具有
Identifiable
协议要求的 id 属性,但我无法将
CustomModel
用作 SwiftUI 中的可识别类型。

protocol CustomProtocol: Identifiable {
    var id: String { get }
}

struct CustomModel: CustomProtocol {
    let id = UUID().uuidString
}

class CustomModelStore: ObservableObject {
    @Published var models: [any CustomProtocol] = []
    
    init() {
        models = Array(repeating: CustomModel(), count: 10)
    }
}

struct CustomProtocolView: View {
    
    @StateObject var store = CustomModelStore()
    @State var selectedModel: (any CustomProtocol)?
    
    var body: some View {
        VStack {
            ForEach(store.models) { model in
                Text(model.id)
                    .font(.footnote)
                    .onTapGesture {
                        selectedModel = model
                    }
            }
            .sheet(item: $selectedModel) { model in
                Text(model.id)
                    .font(.subheadline)
            }
        }
    }
}

struct CustomProtocolView_Previews: PreviewProvider {
    static var previews: some View {
        CustomProtocolView()
    }
}

当然我可以在

id
中指定
ForEach
,但是这种方式对我来说是不可接受的,因为我没有机会在
.sheet
.fullScreenCover
视图修饰符中这样做。在我的商店中,我也无法将类型从
CustomProtocol
更改为
CustomModel

swift swiftui protocols identifiable
1个回答
0
投票

这是标准的“协议存在(

any
类型)不符合协议。”
selectedModel
不符合 CustomProtocol(或 Identifiable)。只有具体类型符合协议。

正如 Baglan 指出的那样,您可以通过传递

id: \.id
来处理 ForEach,但是您必须重新设计
.sheet
以不需要可识别的,或者您需要摆脱
any CustomProtocol
并使用混凝土类型。

具体如何工作在很大程度上取决于 CustomProtocol 的作用以及

models
中的对象类型。如果它们都是同一个对象(就像你的例子),那么你通常会让 CustomModelStore 和 CustomProtocolView 通用:

// Make generic over the model
class CustomModelStore<Model: CustomProtocol>: ObservableObject {
    @Published var models: [Model] = []

    // Initialize with the correct type, not hard-coded CustomModel
//    init() {
//        models = Array(repeating: CustomModel(), count: 10)
//    }
}

// Make generic over the model
struct CustomProtocolView<Model: CustomProtocol>: View {

    @StateObject var store = CustomModelStore<Model>()
    @State var selectedModel: Model?

    // Now your original code is fine.
    var body: some View {
        // ...
    }
}

如果数组中有不同的类型,那么设计正确的解决方案将取决于所有这些的实际工作方式。一般来说,答案是

.map
对象到视图使用的一些具体模型结构而不是底层对象,但这取决于你的问题。

© www.soinside.com 2019 - 2024. All rights reserved.