背景:
我正在尝试根据 Apple 的此示例构建一个 OutlineGroup
:https://developer.apple.com/documentation/swiftui/outlinegroup
但是我不想使用静态类型,而是想使用符合我的协议(protocol)的对象。因此,如果我想做的事情可以很快实现,那么问题就更普遍了:
问题:
我有一个协议(protocol),可以为我提供来自各种对象的同事
和姓名
:
protocol CastProtocol {
var name: String { get }
var coworkers: [CastProtocol]? { get } // here will be the build error later
}
并以两个模型为例:
class Actor: Identifiable, CastProtocol {
var id: Self { self }
var name: String { return "Chuck Norris" }
var coworkers: [CastProtocol]? {
return [
Director()
]
}
}
class Director: Identifiable, CastProtocol {
var id: Self { self }
var name: String { return "Gina Carey" }
var coworkers: [CastProtocol]? {
return [
Actor(),
Director(),
Actor()
]
}
}
到目前为止,一切正常,但我需要确保我的 CastProtocol
符合 Identifying
,因此将我的协议(protocol)实现更改为:
protocol CastProtocol: Identifiable {
...
}
现在这产生了一个问题:
Protocol 'CastProtocol' can only be used as a generic constraint because it has Self or associated type requirements
问题:
- 那么有一种方法可以通过在
coworkers
中返回非静态类型来实现此目的,或者也许我应该使用子类化? - 这是正确的方法吗?也许我唯一缺少的是在协议(protocol)级别标识符要求中声明可识别?但如果是这样 - 怎么办?
- 我认为我真的不能选择关联类型。如果此示例中的
coworkers
可以包含Actor
或Director
关联类型,我认为无法使用
最佳答案
协议(protocol)从不遵守其他协议(protocol)。语法 protocol CastProtocol: Identifying
并不意味着“CastProtocol 符合 Identifying”。它的意思是“为了符合 CastProtocol,类型也必须符合 Identifying。”
对于这个问题,不,你不能要求这样做。 可识别
包括关联的类型ID
。考虑这段代码:
let coworker in coworkers {
let id = coworker.id // What type is `id` here?
...
}
在这种情况下,Swift 无法分配单一类型 id
。有一天,他们可能会添加一个称为“广义存在”的功能,该功能将允许将 id
推断为 Any where Self: Hashable
类型,但目前还无法用以下方式表达这一点: swift 。
但就你的情况而言,无论如何它都无法工作。说你能做到这一点。由于您已将标识符设置为对象本身,因此系统最终需要评估Director == Actor
。这在 Swift 中是不可能的。它们不是同一类型。
相反,我怀疑你想要这个,如果你真的希望 Actor 成员成为类:
protocol CastMember: class {
var name: String { get }
var coworkers: [CastMember] { get } // Optional Arrays are almost always wrong
var id: ObjectIdentifer { get }
}
extension CastMember {
var id: ObjectIdentifier { ObjectIdentifier(self) }
}
// You can still put Identifiable here for [Actor] properties
class Actor: CastProtocol, Identifiable {
// ...
}
现在,这不会让您将它们直接放入 ForEach(actor.coworkers)
调用中,我认为这就是您想要的。就我个人而言,我只是传递 id:\.id
参数,但是如果您经常这样做,您当然可以使用扩展使其变得更好一点:
extension ForEach where Content : View, Data.Element == CastMember {
public init(_ data: Data, @ViewBuilder content: @escaping (Data.Element) -> Content) {
self.init(data, id: \.id, content: content)
}
}
请注意 Data.Element == CastMember
而不是 :
。这适用于 CastMember 数组,而不是符合 CastMember 的事物数组。
关于ios - `Identifiable` 一致性返回类型泛型作为变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63192951/