本文主要介紹在MVC模式下,拆分TableView的代理,實(shí)現(xiàn)不同數(shù)據(jù)源動(dòng)態(tài)創(chuàng)建不同的Cell。
文件結(jié)構(gòu)如下:

文件結(jié)構(gòu)解析
Controllers
這里放的是頁(yè)面的Controller,主要負(fù)責(zé)邏輯加載和設(shè)置TableView的代理
Models
- Items
一個(gè)item對(duì)應(yīng)一個(gè)Cell,對(duì)數(shù)據(jù)的單元封裝 - DataSource
自定義的DataSource子類,用于實(shí)現(xiàn)TableView的UITableViewDataSource代理,并且分發(fā)item與Cell的對(duì)應(yīng)關(guān)系
model主要接收數(shù)據(jù),封裝成item,并加入數(shù)組
Views
- Cells
自定義與item一一對(duì)應(yīng)的Cell
重點(diǎn)解析
TableView有兩個(gè)代理,分別是是UITableViewDelegate和UITableViewDataSource,這里需要重點(diǎn)針對(duì)UITableViewDataSource進(jìn)行一些定制。
LittleHTableViewDataSource
首先我們自己定義一個(gè)協(xié)議LittleHTableViewDataSourcePotocol具體如下:
public protocol LittleHTableViewDataSourcePotocol:NSObjectProtocol,UITableViewDataSource
{
func tableView(_ tableView:UITableView, objectForRowAt indexPath:IndexPath) -> AnyObject?
func tableView(_ tableView: UITableView, cellClassForObject object: AnyObject) -> LittleHTableViewBaseCell.Type
func tableView(_ tableView: UITableView, indexPathForObject object: AnyObject) -> IndexPath?
func tableView(_ tableView: UITableView, cell:UITableViewCell, willAppearAtIndexPath indexPath: IndexPath) -> Void
}
然后我們聲明一個(gè)自定義的DataSource類,實(shí)現(xiàn)LittleHTableViewDataSourcePotocol協(xié)議
public class LittleHTableViewDataSource: NSObject,LittleHTableViewDataSourcePotocol {
public var items : NSArray
public init(items : NSArray) {
self.items = items
}
// MARK:
// MARK: -LittleHTableViewDataSourcePotocol 方法
public func tableView(_ tableView: UITableView, objectForRowAt indexPath: IndexPath) -> AnyObject? {
if indexPath.row < self.items.count {
return self.items.object(at: indexPath.row) as AnyObject?
} else {
return nil
}
}
public func tableView(_ tableView: UITableView, cellClassForObject object: AnyObject) -> LittleHTableViewBaseCell.Type {
return LittleHTableViewBaseCell.self
}
public func tableView(_ tableView: UITableView, indexPathForObject object: AnyObject) -> IndexPath? {
return nil
}
public func tableView(_ tableView: UITableView, cell:UITableViewCell, willAppearAtIndexPath indexPath: IndexPath) -> Void {
}
// MARK:
// MARK: -UITableViewDataSource方法
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let object:AnyObject? = self.tableView(tableView, objectForRowAt: indexPath)
var cell1:UITableViewCell
if let obj1 = object {
let cellClass:LittleHTableViewBaseCell.Type = self.tableView(tableView, cellClassForObject: obj1)
let identifier:String = cellClass.LittleHIdentifier()
var cell:UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: identifier)
if cell == nil {
cell = cellClass.init(style: UITableViewCellStyle.default, reuseIdentifier: identifier)
}
cell1 = cell!
} else {
cell1 = LittleHTableViewBaseCell(style: UITableViewCellStyle.default, reuseIdentifier: nil)
}
if cell1 is LittleHTableViewBaseCell {
let cell2 = cell1 as! LittleHTableViewBaseCell
cell2.setObject(object)
}
return cell1
}
public func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
open func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
if let view1 = tableView.tableHeaderView {
if index == 0 {
tableView.scrollRectToVisible(view1.bounds, animated: false)
return -1
}
}
// let index2 = advance(title.startIndex, 1)
var index2:String.Index = title.startIndex
index2 = title.index(index2, offsetBy: 1)
let letter:String = title.substring(to: index2)
let sectionCount:Int = tableView.numberOfSections
var i:Int = 0
for _ in 1...sectionCount {
let section :String = (tableView.dataSource?.tableView!(tableView, titleForHeaderInSection: i))!
if section.hasPrefix(letter) {
return i
}
i += 1
}
if index > sectionCount {
return sectionCount - 1
} else {
return index
}
}
}
在我們自己定義的這個(gè)DataSource里面可以看到已經(jīng)實(shí)現(xiàn)了UITableViewDataSource,我們通過(guò)LittleHTableViewDataSourcePotocol協(xié)議的
func tableView(_ tableView: UITableView, cellClassForObject object: AnyObject) -> LittleHTableViewBaseCell.Type
方法獲取到具體Cell的classType,然后創(chuàng)建這個(gè)類型的Cell,并且通過(guò)LittleHTableViewDataSourcePotocol協(xié)議的
func tableView(_ tableView:UITableView, objectForRowAt indexPath:IndexPath) -> AnyObject?
方法獲取Cell對(duì)應(yīng)的數(shù)據(jù),在Cell的setObject方法中進(jìn)行數(shù)據(jù)賦值。
Controller關(guān)鍵代碼
在我們使用到tableView的地方,將tableView的UITableViewDataSource代理設(shè)置為這個(gè)類的對(duì)象。如:
public var dataSource : LittleHTableViewDataSource?{
get{
return _dataSource
}
set{
if newValue != _dataSource {
_dataSource = newValue
}
if let tableView1 = self.tableView {
tableView1.dataSource = _dataSource
tableView1.reloadData()
}
}
}
我們希望Cell的高度能在Cell內(nèi)部返回,最好在item數(shù)據(jù)封裝的時(shí)候就直接計(jì)算好Cell的高度,然后直接返回,實(shí)現(xiàn)UITableViewDelegate的下面方法將返回的高度的任務(wù)轉(zhuǎn)移到Cell
open func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if (tableView.dataSource is LittleHTableViewDataSource) {
let dataSource:LittleHTableViewDataSource? = tableView.dataSource as? LittleHTableViewDataSource
if let d1 = dataSource {
let object = d1.tableView(tableView, objectForRowAt: indexPath)
if let obj1 = object {
let t1:LittleHTableViewBaseCell.Type = d1.tableView(tableView, cellClassForObject: obj1)
return t1.tableView(tableView, rowHeightForObject: obj1)
}
}
}
return 44.0
}
Cell
cell上需要實(shí)現(xiàn)
public func setObject (_ obj:AnyObject?) -> Void
來(lái)獲取數(shù)據(jù)
實(shí)現(xiàn)
public class func tableView(_ tableView: UITableView, rowHeightForObject object: AnyObject) -> CGFloat
獲取高度
實(shí)現(xiàn)
public class func LittleHIdentifier() -> String
設(shè)置reuseIdentifier
主要思路,將TableView的UITableViewDataSource的Cell構(gòu)建能夠根據(jù)classType去動(dòng)態(tài)構(gòu)建,把數(shù)據(jù)類型item和Cell一一對(duì)應(yīng)。