[英]Using SwiftUI ForEach to iterate over [any Protocol] where said protocol is Identifiable
In a ViewModel I have:在 ViewModel 我有:
public var models: [any Tabbable]
And Tabbable starts with Tabbable 以
public protocol Tabbable: Identifiable {
associatedtype Id
var id: Id { get }
/// ...
}
In Swift in my ViewModel I can use the Array.forEach to:在我的 ViewModel 中的 Swift 中,我可以使用 Array.forEach 来:
models.forEach { _ in
print("Test")
}
But in SwiftUI I can't use ForEach to:但在 SwiftUI 中,我不能使用 ForEach 来:
ForEach(viewModel.models) { _ in
Text("Test")
}
Due to:由于:
Type 'any Tabbable' cannot conform to 'Identifiable'
类型 'any Tabbable' 不能符合 'Identifiable'
Any suggestions?有什么建议么? This is with Swift 5.7.
这是 Swift 5.7。 Do I need to go back to making something like AnyTabbable?
我需要回去制作像 AnyTabbable 这样的东西吗? Thanks in advance.
提前致谢。
Consider this example in the form of a Playground:以 Playground 的形式考虑这个例子:
import UIKit
import SwiftUI
public protocol Tabbable: Identifiable {
associatedtype Id
var id: Id { get }
var name : String { get }
}
struct TabbableA : Tabbable{
typealias Id = Int
var id : Id = 3
var name = "TabbableA"
}
struct TabbableB : Tabbable {
typealias Id = UUID
var id : Id = UUID()
var name = "TabbableB"
}
struct ViewModel {
public var models: [any Tabbable]
}
let tabbableA = TabbableA()
let tabbableB = TabbableB()
let models: [any Tabbable] = [tabbableA, tabbableB]
struct ContentView {
@State var viewModel : ViewModel = ViewModel(models: models)
var body : some View {
ForEach(viewModel.models) { model in
Text(model.name)
}
}
}
In this case, we have the type TabbableA
where each instance has an id
property that is an integer (for the sake of the sample they only use "3" but it's the type that is significant).在这种情况下,我们有类型
TabbableA
,其中每个实例都有一个整数id
属性(为了示例,他们只使用“3”,但它是重要的类型)。 In TabbableB
each instance's id
is a UUID.在
TabbableB
每个实例的id
都是一个 UUID。 Then I create an array where one item is an instance of TabableA
and another is an instance of TabbableB
.然后我创建一个数组,其中一项是
TabableA
的实例,另一项是TabbableB
的实例。 The array is of type [any Tabbable]
.该数组的类型为
[any Tabbable]
。
Then I try to use ForEach
on the array.然后我尝试在数组上使用
ForEach
。 But some elements in the array use Int
ids and some use UUID
ids.但是数组中的一些元素使用
Int
id,一些使用UUID
id。 The system doesn't know what type to use to uniquely identify views.系统不知道使用什么类型来唯一标识视图。
Ints
and UUIDs
can't be directly compared to one another to determine equality. Ints
和UUIDs
不能直接相互比较以确定相等性。 While each item that went into the array is Tabbable
, and therefore conforms to Identifiable
, the elements coming out of the array, each of which is of type any Tabbable
, do not conform to Identifiable
.虽然进入数组的每个项目都是
Tabbable
,因此符合Identifiable
,但从数组中出来的元素(每个元素的类型any Tabbable
)不符合Identifiable
。 So the system rejects my code.所以系统拒绝了我的代码。
You can provide a KeyPath to the id (or any unique variable): parameter which specifies how to retrieve the ID
in ForEach
.您可以为 id(或任何唯一变量)提供 KeyPath:参数,该参数指定如何在
ForEach
中检索ID
。 It is because all items in ForEach
must be unique.这是因为
ForEach
中的所有项目都必须是唯一的。 You can create a structure, which conforms to your protocol.您可以创建一个符合您的协议的结构。 At that moment it should work.
在那一刻它应该工作。 The second option is to remove
Identifiable
from the protocol and then you can use that directly.第二个选项是从协议中删除
Identifiable
,然后您可以直接使用它。
public protocol Tabbable {
var id: String { get }
/// ...
}
public var models: [Tabbable]
ForEach(viewModel.models, id: \.id) { _ in
Text("Test")
}
or或者
public protocol TabbableType: Identifiable {
associatedtype Id
var id: Id { get }
/// ...
}
struct Tabbable: TabbableType {
var id: String { get }
/// ...
}
public var models: [Tabbable]
ForEach(viewModel.models) { _ in
Text("Test")
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.