Гетерогенный массив универсального объекта, где T отличается - PullRequest
0 голосов
/ 24 января 2019

это мой класс BaseSection, который реализует Collection и выглядит так:

class BaseSection<T:Equatable> {

var items:[T]?

required init(items:[T]){
   self.items = items
  }
}

let sectionTop = BaseSection<TopItem>(items:["foo","bar","yo"])
let sectionBottom = BaseSection<BottomItem>(items:["foo","bar","yo"])

для этой демонстрации я строю секцию строковых объектов, которые Equatable, но мой проект конструирует объект с одним свойством String реализация коллекции здесь не указана. мне нужно держать оба объекта в массиве, и я не могу это сделать, даже если их базовый класс одинаков.

let sections = [sectionTop, sectionBottom]
heterogeneous collection literal could only be inferred to '[Any]' add explicit type annotation....

Я боролся часами со многими решениями, но не смог достичь своей цели здесь. любая помощь будет высоко ценится

Edit: I have uploaded the sample code to gitHub so you can get a better grasp of what im doing 

github Link

Ответы [ 2 ]

0 голосов
/ 27 января 2019

То, что вы, похоже, создаете, - это механизм для автоматизации изменений табличного представления при изменении данных. Очень распространенный. Я настоятельно рекомендую взглянуть на ListDiff для полезной отправной точки при расчете изменений. (В моем собственном коде я использую переписанную версию ListDiff, поэтому мои примеры здесь не проверены, но они должны быть очень близки.)

Цель состоит в том, чтобы создать набор операций обновления (скопированных из примера ListDiff):

import ListDiff

extension Int : Diffable {
    public var diffIdentifier: AnyHashable {
        return self
    }
}
let o = [0, 1, 2]
let n = [2, 1, 3]
let result = List.diffing(oldArray: o, newArray: n)
// result.hasChanges == true
// result.deletes == IndexSet(integer: 0)
// result.inserts == IndexSet(integer: 2)
// result.moves == [List.MoveIndex(from: 2, to: 0), List.MoveIndex(from: 1, to: 1)]
// result.changeCount == 4

Здесь важно то, что у вас есть ряд операций удаления, вставки и перемещения. Вы можете применить их к табличному представлению с чем-то вроде этого:

extension UITableView {
    func applyChanges(from changeset: Result, forSection section: Int = 0) {
        beginUpdates()

        let deletes = changeset.deletes.map { IndexPath(row: $0, section: section) }
        deleteRows(at: deletes, with: .bottom)

        let inserts = changeset.deletes.map { IndexPath(row: $0, section: section) }
        insertRows(at: inserts, with: .none)

        for move in changeset.moves {
            guard !changeset.deletes.contains(move.from) else { continue }
            moveRow(at: IndexPath(row: move.from, section: section), 
                    to: IndexPath(row: move.to, section: section))
        }

        endUpdates()
    }
}

Ключевым моментом здесь является то, что для анимации вам нужны только пути индекса. Вам на самом деле не нужны данные. Так что вычисляйте пути индекса и передавайте их. Дженерики не нужны.

0 голосов
/ 24 января 2019

, поскольку в быстрых настраиваемых универсальных типах все значения инвариантны, это означает, что BaseSection<TopItem> и BaseSection<BottomItem> не имеют отношения, поэтому единственным общим типом этих двух является Any, вы можете перейти по ссылкам в комментариях для получения дополнительной информации,как итог

  1. Массивы / Dict - ковариационные
  2. типы параметров замыкания - контравариантные, тип возврата замыкания - ковариационные
  3. пользовательские универсальные типы являются инвариантными

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

...