【发布时间】:2017-09-07 09:59:21
【问题描述】:
我正在尝试使用协议设计一个强类型的对象层次结构,但不能完全正确。
为了说明,假设最终将采用这些协议的具体类型是 类 Country、State 和 City。
每个节点都可以有一个父节点(根对象除外)和/或子节点(叶对象除外):所有State 实例都是单个Country 实例的子节点,并将其作为父节点,并且它们具有@ 987654326@ 子实例等。
所以我从这两个协议开始:
/// To be adopted by State and City
///
protocol Child: AnyObject {
associatedtype ParentType: AnyObject
// (-> so that property `parent` can be weak)
weak var parent: ParentType? { get }
}
/// To be adopted by Country and State
///
protocol Parent: AnyObject {
associatedtype ChildType: AnyObject
// (-> for symmetry)
var children: [ChildType] { get }
}
我有两个单独的协议,而不是一个组合所有上述要求的协议,因为我不想为根类 Country 指定一个“虚拟”typealias ParentType(这是没有意义的),也不是叶类City的“虚拟”typealias ChildType。
取而代之,我可以将父子行为分开,只让中间类State采用两种协议。
接下来,我想让我的类可以从从磁盘读取的字典中初始化。对于子类,我想在实例化的时候指定父类,所以想出了这个方案:
protocol UnarchivableChild: Child {
init(dictionary: [String: Any], parent: ParentType?)
}
protocol UnarchivingParent: Parent {
associatedtype ChildType: UnarchivableChild
func readChildren(fromDictionaries dictionaries: [[String: Any]]) -> [ChildType]
}
就目前而言,看起来我可以更进一步,添加方法 readChildren(fromDictionaries:) 的默认实现,如下所示:
extension UnarchivingParent {
func readChildren(fromDictionaries dictionaries: [[String: Any]]) -> [ChildType] {
return dictionaries.flatMap({ dictionary in
return ChildType(dictionary: dictionary, parent: self)
})
}
}
...因为在这个协议中,ChildType 被限制为UnarchivableChild,所以它应该支持初始化器...?但我明白了:
无法使用类型为“(字典:([String : Any]),父级:Self)”的参数列表调用“ChildType”
(为什么是大写的“Self”?)
我想我遗漏了一些关于关联类型如何工作的东西......
如何编码这个默认实现?
更新:显然,传递 self 是个问题。我将代码修改为:
protocol Node: AnyObject {
}
protocol Parent: Node {
associatedtype ChildNodeType: Node
var children: [ChildNodeType] { get set }
}
protocol Child: Node {
associatedtype ParentNodeType: Node
weak var parent: ParentNodeType? { get set }
}
protocol UnarchivableChild: Child {
init(dictionary: [String: Any]) // Removed parent parameter!
}
protocol UnarchivingParent: Parent {
associatedtype ChildNodeType: UnarchivableChild
func readChildren(fromDictionaries dictionaries: [[String: Any]]) -> [ChildNodeType]
}
extension UnarchivingParent {
func readChildren(fromDictionaries dictionaries: [[String: Any]]) -> [ChildNodeType] {
return dictionaries.flatMap({
let child = ChildNodeType(dictionary: $0)
// Assign parent here instead:
child.parent = self // < ERROR HERE
return child
})
}
}
错误是:
无法将类型“Self”的值分配给类型“_?”
【问题讨论】: