使用 SwiftUI ForEach 迭代[任何协议],其中所述协议是可识别的

Bre*_*anS 6 swift swiftui

在 ViewModel 中我有:

public var models: [any Tabbable]
Run Code Online (Sandbox Code Playgroud)

Tabbable 开头为

public protocol Tabbable: Identifiable {
   associatedtype Id
   var id: Id { get }
   /// ...
}
Run Code Online (Sandbox Code Playgroud)

在我的 ViewModel 中的 Swift 中,我可以使用 Array.forEach 来:

models.forEach { _ in
   print("Test")
}
Run Code Online (Sandbox Code Playgroud)

但在 SwiftUI 中我无法使用 ForEach 来:

ForEach(viewModel.models) { _ in
   Text("Test")
}
Run Code Online (Sandbox Code Playgroud)

由于:

类型“任何 T​​abbable”不能符合“可识别”

有什么建议么?这是 Swift 5.7 的情况。我需要回去制作像 AnyTabbable 这样的东西吗?提前致谢。

Sco*_*son 8

以 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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我们的类型TabbableA中每个实例都有一个id整数属性(为了示例,他们只使用“3”,但它是重要的类型)。TabbableB每个实例都有id一个 UUID。然后我创建一个数组,其中一项是 的实例TabableA,另一项是 的实例TabbableB。该数组的类型为[any Tabbable]

ForEach然后我尝试在数组上使用。但数组中有些元素使用Intids,有些元素使用UUIDids。系统不知道使用什么类型来唯一标识视图。Ints并且UUIDs不能直接相互比较来确定相等性。虽然进入数组的每个项目都是Tabbable,因此符合Identifiable,但从数组中出来的元素(每个元素的类型都是any Tabbable却不符合Identifiable。所以系统拒绝了我的代码。

另一种思考方式:类型为 的值是any SomeProtocol一个盒子,可以包含符合 的任何内容SomeProtocol,但盒子本身符合SomeProtocol