原文:如何在Swift中優(yōu)雅地使用ReusableIdentifier
蘋果為了保準UITableView視圖的性能蚂维,使用了cell的重用機制,cell可以通過重用標示符(reusableIdentifier)進行復用,默認的注冊cell和獲取cell的方法中,需要傳入一個字符串作重用標示符后添。但這種方式很容易出錯笨枯,而且使用起來也相當別扭薪丁,一種普遍的解決方式,就是直接只用類名作為重用標示符:
tableview.registerClass(UITableViewCell.self, forCellReuseIdentifier: String(UITableViewCell.self))
tableview.dequeueReusableCellWithIdentifier(String(UITableViewCell.self))
但這種寫法依然頗為繁瑣馅精,每次都要傳入一個類严嗜,并把它轉(zhuǎn)化成字符串。所幸洲敢,借助Swift的泛型特性漫玄,我們可以有更加優(yōu)雅的實現(xiàn)方式。
使用協(xié)議
在使用泛型來優(yōu)化 TableView Cells 的使用體驗這篇文章中压彭,作者詳細介紹了如何通過協(xié)議+泛型的方式睦优,優(yōu)化TableView Cells 的使用體驗。具體的做法很簡單壮不,首先聲明了一個協(xié)議汗盘,提供并默認實現(xiàn)了一個reuseIdentifier
靜態(tài)屬性:
protocol Reusable: class {
static var reuseIdentifier: String { get }
}
extension Reusable {
static var reuseIdentifier: String {
return String(Self)
}
}
然后提供一個注冊和獲取重用cell的方法:
func registerReusableCell<T: UITableViewCell where T: Reusable>(_: T.Type) {
self.registerClass(T.self, forCellReuseIdentifier: T.reuseIdentifier)
}
func dequeueReusableCell<T: UITableViewCell where T: Reusable>(indexPath indexPath: NSIndexPath) -> T {
return self.dequeueReusableCellWithIdentifier(T.reuseIdentifier, forIndexPath: indexPath) as! T
}
這樣只要cell遵守了Reusable
協(xié)議,就可以通過上面兩個方法注冊復用cell了询一。具體的代碼和使用隐孽,請閱讀原文:使用泛型來優(yōu)化 TableView Cells 的使用體驗
這種方式的確是比原生的方法方便了不少,但還是有一個不太方便的地方健蕊,那就是cell必須遵守了Reusable
協(xié)議菱阵,雖然我們可以通過讓UITableViewCell
遵守這個協(xié)議的方式,避免每個UITableViewCell
子cell都寫一遍缩功,但這依然還不是最理想的解決方式晴及。最理想的解決方式,應該是只需要調(diào)用方法嫡锌,不需要UITableViewCell
做任何修改抗俄,為此我們可以使用結(jié)構(gòu)體脆丁,而非協(xié)議來實現(xiàn)。
使用結(jié)構(gòu)體
我們可以使用泛型定義一個ReusableIdentifier
結(jié)構(gòu)體动雹,有一個identifier
的不變量:
public struct ReusableIdentifier <T: UIView> {
let identifier: String
init() {
identifier = String(T.self)
}
}
然后為UITableView
實現(xiàn)一個register
方法槽卫,這個方法只需要傳入一個類型即可:
extension UITableView {
func register<T: UITableViewCell>(_: T.Type) {
registerClass(T.self, forCellReuseIdentifier: ReusableIdentifier<T>().identifier)
}
}
如此,注冊的時候就非常簡單:tableview.register(UITableViewCell.self)
胰蝠。
同樣的歼培,可以為UITableView
實現(xiàn)一個dequeue
方法:
@warn_unused_result
func dequeue<T: UICollectionViewCell>(indexPath: NSIndexPath) -> T {
let rid = ReusableIdentifier<T>()
guard let cell = dequeueReusableCellWithReuseIdentifier(rid.identifier, forIndexPath: indexPath) as? T else {
assertionFailure("No identifier(\(rid.identifier)) found for \(T.self)")
return T.init()
}
return cell
}
使用的時候只需要指定cell的類型,傳入indexPath即可:
let cell: UITableViewCell = tableview.dequeue(indexPath)
通過引入一個結(jié)構(gòu)體茸塞,利用泛型特性躲庄,不需要對已有的類型做任何修改,只需要替換注冊和復用cell時調(diào)用的方法钾虐,我們就可以非常優(yōu)雅的復用Tableview Cell噪窘。
參考上面的方法,我們可以借助ReusableIdentifier
結(jié)構(gòu)體效扫,為UICollectionView
實現(xiàn)相應的方法倔监。