Тип класса Swift Generic Protocol в массиве - PullRequest
3 голосов
/ 18 апреля 2019

Мы реализовали протокол, Reusable, для упрощения UITableView реализаций регистрации / удаления для наших UITableViewCell s.

protocol Reusable: class {
    static var defaultIdentifier: String { get }
}

extension Reusable where Self: UITableViewCell {
    static var defaultIdentifier: String {
        return String(describing: self)
    }
}

class TestTableViewCell: UITableViewCell, Reusable { }
class AnotherTestTableViewCell: UITableViewCell, Reusable { }

Затем есть расширение к UITableView, например:

extension UITableView {
    func register<T: UITableViewCell & Reusable>(_: T.Type) {
        register(UINib(nibName: T.defaultIdentifier, bundle: nil), forCellReuseIdentifier: T.defaultIdentifier)
    }
}

и как его использовать:

let tableView: UITableView = UITableView()
tableView.register(TestTableViewCell.self)
tableView.register(AnotherTableViewCell.self)

Все работает хорошо, но мы бы хотели переместить эти типы в массив для порядка.Вот где мы застряли, это не работает:

let viewCells = [TestTableViewCell.self, AnotherTestTableViewCell.self]
// Without type annotation, it's [UITableViewCell.Type]
// And the error is: Instance method 'register' requires that 'UITableViewCell' conform to 'Reusable'

for viewCell in viewCells {
    tableView.register(viewCell)
}

Мы также попробовали:

let viewCells: [Reusable.Type] = ...
// Error: Cannot invoke 'register' with an argument list of type '(Reusable.Type)'

Также это:

let viewCells: [(UITableViewCell & Reusable).Type] = ...
// Error: Instance method 'register' requires that 'UITableViewCell' conform to 'Reusable'

IsЕсть ли способ сохранить информацию типа класса с соответствием протокола в массиве, чтобы заставить эту работу?

Ответы [ 4 ]

3 голосов
/ 18 апреля 2019

Просто напишите расширение для UITableViewCell, чтобы оно соответствовало протоколу Reusable и не приводили ячейки к какому-либо типу:

extension UITableViewCell: Reusable {}

PS вы также можете проверить самую популярную реализацию протокола Reusable на iOS здесь .

Удачи:)

2 голосов
/ 18 апреля 2019
protocol Reusable: class {
    static var defaultIdentifier: String { get }
}

extension Reusable where Self: UITableViewCell {
    static var defaultIdentifier: String {
        return String(describing: self)
    }
}

class TestTableViewCell: UITableViewCell, Reusable { }
extension UITableView {
    func register<T: UITableViewCell & Reusable>(_: T.Type) {
        register(UINib(nibName: T.defaultIdentifier, bundle: nil), forCellReuseIdentifier: T.defaultIdentifier)
    }
}
let tableView: UITableView = UITableView()
tableView.register(TestTableViewCell.self)
let viewCells = [TestTableViewCell.self]
// Without type annotation, it's [UITableViewCell.Type]
// And the error is: Instance method 'register' requires that 'UITableViewCell' conform to 'Reusable'

for viewCell in viewCells {
    tableView.register(viewCell)
}

Этот код успешно выполняется.

1 голос
/ 18 апреля 2019

Надеюсь, вы счастливы с этим.Ключом является Self ключевое слово в протоколе.

protocol Reusable: class {
    static var defaultIdentifier: String { get }
    static func register(tableView: UITableView)
}

extension Reusable where Self: UITableViewCell {
    static var defaultIdentifier: String {
        return String(describing: self)
    }

    static func register(tableView: UITableView) {
        tableView.register(UINib(nibName: Self.defaultIdentifier, bundle: nil), forCellReuseIdentifier: Self.defaultIdentifier)
    }
}

extension UITableView {
    func register(_ reusable: Reusable.Type) {
        reusable.register(tableView: self)
    }
}

let viewCells: [Reusable.Type] = [TestTableViewCell.self, AnotherTestTableViewCell.self]

for viewCell in viewCells {
    tableView.register(viewCell)
}

Я рекомендую вам прочитать следующие ссылки:

0 голосов
/ 18 апреля 2019

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

 extension UITableView {
     func registerCell<T: UITableViewCell>(cellType: T.Type) {
        let nib = UINib(nibName: String(describing: cellType.self), bundle: nil)
        let reuseIdentifier = String(describing: cellType.self)
        self.register(nib, forCellReuseIdentifier: reuseIdentifier)
     }
} 

И используйте его вот так

 let tableView: UITableView = UITableView()
    let cellsArray = [Test.self, Test1.self, Test2.self]
    for cell in cellsArray {
        tableView.registerCell(cellType: cell)
    }
...