【发布时间】:2019-10-26 10:11:12
【问题描述】:
我正在试验 SwiftUI,并在为我的一个 List 实现数据模型时遇到了一个问题。我的计划是创建一个协议CardProtocol 作为我列表元素的数据协议,然后有一个协议的 CoreData 实现以及一个用于单元测试和 Canvas 使用的虚拟协议。如果您在 SwiftUI List 中使用数据集合,则单个元素需要符合 Identifiable 协议。
代码如下所示:
import SwiftUI
import Combine
final class CardsModel: BindableObject {
var cards: [CardProtocol] = []
let didChange = PassthroughSubject<CardsModel, Never>()
}
protocol CardProtocol: Identifiable {
var id: Int { get set }
var firstName: String? { get set }
var lastName: String? { get set }
var email: String? { get set }
var phone: String? { get set }
}
这甚至不会编译,因为Identifiable 协议有 2 个关联类型,如果协议要用于变量定义,则需要指定这些类型。
/// A type that can be compared for identity equality.
public protocol Identifiable {
/// A type of unique identifier that can be compared for equality.
associatedtype ID : Hashable
/// A unique identifier that can be compared for equality.
var id: Self.ID { get }
/// The type of value identified by `id`.
associatedtype IdentifiedValue = Self
/// The value identified by `id`.
///
/// By default this returns `self`.
var identifiedValue: Self.IdentifiedValue { get }
}
确切的错误是error: protocol 'CardProtocol' can only be used as a generic constraint because it has Self or associated type requirements。
现在ID 不是问题并且可以修复,但IdentifiedValue 在CoreData 和虚拟实现中本质上是不同的。
我发现唯一合理的解决方案是从协议中删除对Identifiable 的遵从性,然后稍后在视图中使用cardsModel.cards.identified(by: \.id) 重新引入它。有没有更好的方法来解决这个问题,让我在协议级别保持可识别的合规性?
【问题讨论】:
-
cardsModel.cards.identified(by: \.id)似乎是更清洁的解决方案,样板更少 -
虽然不是最优的,但我仍然希望将其作为协议。另一种不是最佳的方法是使每个实现独立地符合
Identifiable。