Swift Array of Tuples с общими элементами кортежей - PullRequest
0 голосов
/ 19 февраля 2019

Нужна помощь для моделирования ниже с Swift.Я хотел бы создать массив кортежей, Array<Tuple>, который имеет три элемента каждый

  1. поле String
  2. либо Array<SomeElement>, либо AnyRealmCollection<SomeObject>
  3. замыкание, которое действует на определенные SomeElement или SomeObject.

    Например, Array<Tuple> может захватывать:

    [("section1", AnyRealmCollection<Car>(), {}),
     ("section2", Array<Driver>(), {},
     ("section3", AnyRealmCollection<Passenger>(), {}
    ]

Затем в отдельном методе forEach для каждого кортежа в массиве запускается соответствующее замыкание для обработки каждого объекта SomeElement / SomeObject в пределах Array<SomeElement> или AnyRealmCollection<SomeObject>.

С этой моделью я надеюсь, что смогу поменять местами другие SomeElement / SomeObject, легко добавлять новые записи в Array<Tuple> безопасным способом Type.

Любой совет?

Ответы [ 2 ]

0 голосов
/ 19 февраля 2019

Ваш список требований отлично, и переводится непосредственно в тип.Во-первых, давайте изложим это точно так, как вы сказали.Везде, где вы бы сказали «и», это структура (или класс или кортеж, но в данном случае структура), и везде, где вы бы сказали «или», это перечисление в 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) }
    }
}
0 голосов
/ 19 февраля 2019

Вы не можете иметь массив различных типов, как упомянуто, но вы можете использовать протокол, которому должны соответствовать элементы в массиве.Но, насколько я знаю, вы не можете заставить кортеж соответствовать протоколу, а структура может.

Итак, давайте создадим протокол для элементов массива

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()
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...