我试图使用协议设计一个强类型的对象层次结构,但不能完全正确。
为了说明,假设最终采用这些协议的具体类型是类 Country
,State
和City
。
每个节点都可以有一个父节点(根对象除外)和/或子节点(叶子对象除外):所有State
个实例都是单个Country
实例的子节点,并将其作为父节点,并且他们有City
个实例作为孩子等。
所以我从这两个协议开始:
/// 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 }
}
我有两个单独的协议,而不是将所有上述要求分组的协议,因为我不想指定"虚拟" typealias ParentType
用于根类Country
(没有意义),也不是"虚拟"}叶类typealias ChildType
的{{1}}。
相反,我可以将父行为和子行为分开,只让中间类City
采用两种协议。
下一步,我想从磁盘读取的字典中初始化我的clases。对于子类,我想在实例化时指定父类,所以我提出了这个方案:
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
,所以它应该支持初始化程序......?但我明白了:
无法调用' ChildType'使用类型'的参数列表(字典:([String:Any]),parent:Self)'
(为何大写"自我"?)
我想我错过了关于相关类型如何工作的内容......
如何对此默认实施进行编码?
更新:显然,以某种方式传递自我是个问题。我将代码修改为:
UnarchivableChild
错误是:
无法分配类型' Self'输入' _?'
答案 0 :(得分:0)
阅读The Swift Programmng Language: Generics后的章节:" Generci Where Clause&#34的扩展;),我找到了合适的语法来实现我想要的。我决定使用这个代码(类型名称与原始问题中的名称略有不同):
protocol DictionaryInitializable {
init(dictionary: [String: Any])
}
protocol ChildNode: AnyObject {
associatedtype ParentType: AnyObject
weak var parent: ParentType? { get set }
}
protocol ParentNode {
associatedtype ChildType: AnyObject
var children: [ChildType] { get set }
}
// This 'WHERE' clause fixes the issue:
extension ParentNode where ChildType: DictionaryInitializable,
ChildType: ChildNode, ChildType.ParentType == Self {
func readChildren(from dictionaries: [[String: Any]]) -> [ChildType] {
return dictionaries.map({
return ChildType(dictionary: $0)
})
}
}
where子句的第一个约束允许我调用初始值设定项init(dictionary:)
,第二个约束保证属性parent
的存在,第三个约束允许我指定self
作为其值。
或者,我可以改变:
protocol ParentNode {
associatedtype ChildType: AnyObject
为:
protocol ParentNode {
associatedtype ChildType: ChildNode
...并跳过第二个约束。