简体   繁体   English

数组中的Swift通用协议类类型

[英]Swift Generic Protocol Class Type in Array

We have implemented a protocol, Reusable , to ease UITableView register/dequeue implementations, for our UITableViewCell s. 我们已经实现了一个协议, Reusable ,以缓解UITableView注册/出队的实现,为我们UITableViewCell秒。

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 { }

Then, there's an extension to UITableView like: 然后,有一个UITableView的扩展,如:

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

and as its usage: 以及它的用法:

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

Everything works well, but we'd like to move these types to an array, for order. 一切都运行良好,但我们想将这些类型移动到一个数组,以便订购。 That's where we're stuck, this doesn't work: 这就是我们陷入困境的地方,这不起作用:

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)
}

We've also tried: 我们也尝试过:

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

Also this: 这个:

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

Is there a way to store the class type info with protocol conformance in an array to make this work? 有没有办法将类型信息与协议一致性存储在一个数组中以使其工作?

Just write an extension for UITableViewCell so it conforms to Reusable protocol and do not cast cells to any type: 只需为UITableViewCell编写一个扩展,使其符合Reusable协议,不要将单元格转换为任何类型:

extension UITableViewCell: Reusable {}


PS you can also check the most popular Reusable protocol implementation on iOS here . PS你也可以在这里检查iOS上最流行的Reusable协议实现。


Good luck :) 祝好运 :)

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)
}

This code successfully executes. 此代码成功执行。

Hope you are happy with this. 希望你对此感到高兴。 The key is Self keyword in protocol. 关键是协议中的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)
}

I recommend you to read the following links: 我建议你阅读以下链接:

Simply use this table view extension method to register the cell. 只需使用此表视图扩展方法来注册单元格。

 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)
     }
} 

And use it like so 并像这样使用它

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM