我有一组Realm模型,它们希望在模块内可写,而在模块外是只读的。
我从类的层次结构(组织层次结构,而不是继承)开始,或多或少看起来像这样:
@objcMembers class Section: Object {
dynamic var number: Int = 0
dynamic var name: String = ""
let subsections = List<Subsection>()
}
要获得所需的类本身以及Realm管理的dynamic var
属性的可见性非常简单:
@objcMembers public class Section: Object {
public internal(set) dynamic var number: Int = 0
public internal(set) dynamic var name: String = ""
// ...
}
但是,孩子Lists
存在更多问题。实际上,该列表被声明为let
,因此该字段本身是只读的;但是Realm的List
本身是可变的。在深入研究Realm来源和一些典型的错误开始(trying to use protocols with associated types as return types等)之后,我将Lists
(符合RandomAccessCollection
)包装在AnyRandomAccessCollection
中:
internal let _subsections = List<Subsection>()
public func subsections() -> AnyRandomAccessCollection<Subsection> {
return AnyRandomAccessCollection(_subsections)
}
当我尝试更新单元测试时,其中一些正在使用List
索引访问Int
:
// Good
let subsections: List<Subsection> = section.subsections
let subsection0: Subsection = subsections[0]
我明白了
// Bad
let subsections: AnyRandomAccessCollection<Subsection> = section.subsections()
let subsection0: Subsection = subsections[0]
不能使用索引类型为“ Int”的“ AnyRandomAccessCollection
”下标
我对Swift还是很陌生,仍然被我的Java和C#泛型背景不断误入歧途,但是潜在的问题似乎是Collection
声明了两个关联的类型,Element
和{ {1}},但是Index
仅提供AnyCollection
作为通用参数。经过进一步的挖掘后,我发现了Element
,并点击了以下内容:
AnyIndex
这有效,测试通过了,但是看起来很漂亮。对于我来说,为什么尚不明显(如果底层的let subsections: AnyRandomAccessCollection<Subsection> = section.subsections()
let subsection0: Subsection = subsections[AnyIndex(0)]
没有被List
下标会起作用吗?),这与任何天真的尝试使用返回的对象。我几乎觉得我最好编写自己的符合Int
协议的包装器类,除了我不想陷入实现数十种传递方法的麻烦之外。
这真的是将领域RandomAccessCollection
(或其他一些List
)公开为具有相关元素和索引类型的只读RandomAccessCollection
的最直接方法吗?还是有一些我不知道的更简单的基于泛型或基于类型擦除的解决方案?