需要帮助使用Swift建立以下模型。我想构建一个元组数组Array<Tuple>
,该数组每个都有三个元素
Array<SomeElement>
或AnyRealmCollection<SomeObject>
作用于特定SomeElement
或SomeObject
的闭包。
例如,Array<Tuple>
可以捕获:
[("section1", AnyRealmCollection<Car>(), {}),
("section2", Array<Driver>(), {},
("section3", AnyRealmCollection<Passenger>(), {}
]
然后,使用另一种方法,对于Array中每个元组,触发相应的闭包以处理Array<SomeElement>
或AnyRealmCollection<SomeObject>
中的每个SomeElement / SomeObject。
使用此模型,我希望能够交换其他SomeElement / SomeObject,并以类型安全的方式轻松地向Array<Tuple>
添加新条目。
有什么建议吗?
答案 0 :(得分:1)
您不能具有如上所述的不同类型的数组,但是可以使用该数组中的元素需要遵循的协议。但是据我所知,您不能使元组符合协议,但是结构可以。
让我们为数组项创建协议
protocol TupleHandler {
func iterate() -> Void
}
和符合协议并模仿您的元组的结构
struct TupleStruct<T> : TupleHandler {
var string: String
var array: [T]
var action: (T)->Void
func iterate() {
array.forEach({ action($0) })
}
}
然后可以像
一样使用let ts1 = TupleStruct<String>(string: "abc", array: ["A", "B", "C"], action: { print($0) })
let ts2 = TupleStruct<Int>(string: "def", array: [3, 5, 7], action: { print($0 * 2) })
let array: [TupleHandler] = [ts1, ts2]
for item in array {
item.iterate()
}
答案 1 :(得分:0)
您的需求列表非常好,并且可以直接转换为类型。首先,让我们完全按照您说的说出来。在任何您要说“和”的地方都是一个结构(或类或元组,但在这种情况下是一个结构),在任何您要说“或”的地方都是Swift中的枚举。
struct Model<Element> {
// 1. a String field
let string: String
// 2. either an Array<SomeElement>, or AnyRealmCollection<SomeObject>
enum Container {
case array([Element])
case realmCollection(AnyRealmCollection<Element>)
}
let elements: [Container]
// 3. a closure that acts upon the specific SomeElement or SomeObject.
let process: (Element) -> Void
}
编辑:实际上,这里不可能创建.realmCollection案例,因为AnyRealmCollection对Element提出了附加要求。要解决此问题,您必须围绕AnyRealmCollection构建一个额外的包装器,以消除需求。 It's not hard, but it's tedious,,除非您确实需要区分AnyRealmCollection和AnyCollection,否则我会避免这种情况。
“数组或领域集合”可能比您真正的意思更精确。我怀疑您的意思是“元素的集合”。如果这就是您的意思,那么我们可以更轻松地说:
struct Model<Element> {
let string: String
let elements: AnyCollection<Element>
let process: (Element) -> Void
}
除了强制调用者将元素包装在AnyCollection
中之外,我还将提供以下初始化:
init<C>(string: String, elements: C, process: @escaping (Element) -> Void)
where C: Collection, C.Element == Element {
self.string = string
self.elements = AnyCollection(elements)
self.process = process
}
通常,避免在Swift中使用元组,除非它是非常简单且短暂的东西。 Swift元组非常有限,并且构造一个结构太简单,以至于无法在元组的所有限制上浪费时间。
但是,不能将该类型放入具有不同Elements的数组中。如果这是使用Model的唯一方法,并且您不必将元素取回,则可以使其非通用:
struct Model {
let string: String
let process: () -> Void
init<C: Collection>(_ string: String,
_ elements: C,
_ process: @escaping (C.Element) -> Void) {
self.string = string
self.process = { elements.forEach(process) }
}
}
let list = [Model("section1", AnyRealmCollection<Car>(), { _ in return }),
Model("section2", Array<Driver>(), { _ in return }),
Model("section3", AnyRealmCollection<Passenger>(), { _ in return })
]
如果有时您需要一个模型,有时又需要将其放入不知道元素的数组中,那么可以改用类型擦除器:
struct AnyModel {
let string: String
let process: () -> Void
init<Element>(_ model: Model<Element>) {
self.string = model.string
self.process = { model.elements.forEach(model.process) }
}
}