Ваш список требований отлично, и переводится непосредственно в тип.Во-первых, давайте изложим это точно так, как вы сказали.Везде, где вы бы сказали «и», это структура (или класс или кортеж, но в данном случае структура), и везде, где вы бы сказали «или», это перечисление в 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 накладывает дополнительные требования на элемент.Чтобы это исправить, вам нужно создать дополнительную оболочку вокруг AnyRealmCollection, которая стирает требование. Это не сложно, но это утомительно, , и я бы избегал этого, если только вам действительно не нужно отличать AnyRealmCollection от AnyCollection.
Это «массив или коллекция областей»вероятно, точнее, чем вы на самом деле имеете в виду.Я подозреваю, что вы действительно имеете в виду «набор элементов».Если это то, что вы имеете в виду, тогда мы можем сказать это немного проще:
struct Model<Element> {
let string: String
let elements: AnyCollection<Element>
let process: (Element) -> Void
}
Вместо того, чтобы заставлять вызывающую сторону обернуть элементы в AnyCollection
, я бы также предоставил следующий init:
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 очень ограничены, а создание структуры слишком просто, чтобы тратить время на все ограничения кортежей.
Однако этот тип нельзя поместить в массив с различными элементами.Если это единственный способ использования модели, и вам никогда не нужно возвращать элементы обратно, вы можете просто сделать ее неуниверсальной:
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) }
}
}