之前在網(wǎng)上看到一個OC封裝的父類,即把網(wǎng)絡(luò)請求,網(wǎng)絡(luò)出錯處理,沒有數(shù)據(jù)處理,tableView的上下拉刷新,tableView的dataSource和delegate,cell的初始化,高度的計算,分頁等都封裝到父類.方便開發(fā)使用,無需每次都敲一遍.
這邊我自己用Swift3.1又實現(xiàn)了一遍(其中有封裝的比較簡單的父類,也有封裝比較全的父類)并且將其進行了改進(個人認(rèn)為是改進),方便開發(fā)使用,去除了重復(fù)的代碼與工作.
開始使用吧(這邊以使用封裝好的表格父類為例,例子中數(shù)據(jù)來源是快遞的查詢API,需要傳遞快遞的編號,寫得時候我的那個快遞還沒到,以后可能數(shù)據(jù)信息會失效,故自己把快的編號換成一個你自己的淘寶剛下單的寶貝快的編號(postid),對應(yīng)的快遞公司的編號(type)也要修改)免費的快遞查詢API地址點擊這里
第一步創(chuàng)建start
創(chuàng)建一個實現(xiàn)遵循父協(xié)議PJBaseTableViewDataSourceAndDelegate的類PJTableViewDemoDataSource,父協(xié)議PJBaseTableViewDataSourceAndDelegate遵循NSObject,UITableViewDataSource,UITableViewDelegate,PJBaseTableViewDataSourceDelegate協(xié)議,其中PJBaseTableViewDataSourceDelegate協(xié)議的定義如下:
protocol PJBaseTableViewDataSourceDelegate{
/**
* 子類必須實現(xiàn)協(xié)議,以告訴表格每個model所對應(yīng)的cell是哪個
*/
func tableView(tableView: UITableView, cellClassForObject object: AnyObject?) -> AnyClass
/**
*若為多組需要子類重寫
*/
func tableView(tableView: UITableView, indexPathForObject object: AnyObject) -> NSIndexPath?
func tableView(tableView: UITableView, objectForRowAtIndexPath indexPath: IndexPath) -> AnyObject?
/// MARK: 子類可以重寫以獲取到剛初始化的cell,可在此時做一些額外的操作
func pj_tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath, cell: UITableViewCell,object:AnyObject?)
}
PJTableViewDemoDataSource類必須實現(xiàn):
// MARK: /***********必須重寫以告訴表格什么數(shù)據(jù)模型對應(yīng)什么cell*************/
override func tableView(tableView: UITableView, cellClassForObject object: AnyObject?) -> AnyClass {
if let _ = object?.isKind(of: 數(shù)據(jù)模型類型){
return 返回對應(yīng)cell類型
}
return super.tableView(tableView: tableView, cellClassForObject: object)
}
創(chuàng)建一個控制器繼承表格父類
class PJTableViewDemoController: PJBaseTableViewController(**表格父類**)
定一個PJTableViewDemoDataSource屬性:
lazy var pjTableViewDemoDataSource : PJTableViewDemoDataSource = {
let tempDataSource = PJTableViewDemoDataSource(dataSourceWithItems: nil)
// TODO: /*******cell點擊事件*******/
tempDataSource.cellClickClosure = {
(tableView:UITableView,indexPath : IndexPath,cell : UITableViewCell,object : Any?) in
PJSVProgressHUD.showSuccess(withStatus: "點擊了cell")
}
// TODO: /************cell的子控件的點擊事件************/
tempDataSource.subVieClickClosure = {
(sender:AnyObject?, object:AnyObject?) in
}
return tempDataSource
}()
到這邊創(chuàng)建工作end
第二步使用start
在PJTableViewDemoController類中實現(xiàn)以下方法:
/**
* 子類重寫
*/
extension PJTableViewDemoController{
/**
* 網(wǎng)絡(luò)請求完成
*/
override func requestDidFinishLoad(success: AnyObject?, failure: AnyObject?) {
if let response = success{
let expressModel : ExpressModel = ExpressModel.mj_object(withKeyValues: response)
self.updateView(expressModel: expressModel)
}
}
func updateView(expressModel : ExpressModel){
// TODO: - 注意此處添加網(wǎng)絡(luò)返回的數(shù)據(jù)到表格代理數(shù)據(jù)源中
self.pjTableViewDemoDataSource.addItems(items: expressModel.data)
// TODO: - 更新表格顯示self.createDataSource(),該調(diào)用會在父類進行,子類無需再次手動調(diào)用
}
/**
* 網(wǎng)絡(luò)請求失敗
*/
override func requestDidFailLoadWithError(failure: AnyObject?) {
}
/**
* 以設(shè)置tableView數(shù)據(jù)源
*/
override func createDataSource(){
self.dataSourceAndDelegate = self.pjTableViewDemoDataSource
}
// MARK: 網(wǎng)絡(luò)請求地址
override func getRequestUrl() -> String{
return "http://www.kuaidi100.com/query"
}
// MARK: 網(wǎng)絡(luò)請求參數(shù)
override func getParams() -> [String:Any]{
return ["type":"shentong","postid":"3330209976637"]
}
}
方法是以重寫的方式,故需要重寫的可以重寫,無需的即不必重寫
到這里只需要self.doRequest()(在viewDidLoad中調(diào)用即可)就完成一個從網(wǎng)絡(luò)加載數(shù)據(jù)并且顯示在tableView的操作,并且已經(jīng)封裝好上下拉刷新,分頁等.end
!!!!!!備注:關(guān)于cell高度的計算分為自動計算與手動計算,默認(rèn)自動計算,自動計算時-->注意label如果是有換行的需要設(shè)置preferredMaxLayoutWidth屬性,否則在iOS10等系統(tǒng)上label無法自動換行<--,這邊的自動計算高度用的是FDTemplateLayoutCel(自動布局模式,當(dāng)然可以自行添加frame計算模式),相關(guān)代碼:
/**
計算cell高度的方式,自動計算(利用FDTemplateLayoutCell庫)和手動frame計算,默認(rèn)自動計算,如果是手動計算則cell子類需要重寫class func tableView(tableView: UITableView, rowHeightForObject model: AnyObject?,indexPath:IndexPath) -> CGFloat
**注意label如果是有換行的需要設(shè)置preferredMaxLayoutWidth屬性,否則在iOS10等系統(tǒng)上label無法自動換行**
*/
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//自動計算cell高度(帶有緩存)
if self.isAutoCalculate{
return tableView.fd_heightForCell(withIdentifier: cellID, cacheBy: indexPath) { [weak self] (cell : Any?) in
guard let tempCell = cell as? PJBaseTableViewCell else{
return
}
//自動計算cell高度
tempCell.setModel(model: self?.tableView(tableView: tableView, objectForRowAtIndexPath: indexPath))
}
}else{
return self.getHeightForRow(tableView: tableView, atIndexPath: indexPath)
}
}
/**
獲取cell的高度
*/
func getHeightForRow(tableView:UITableView, atIndexPath indexPath:IndexPath) -> CGFloat{
let object = self.tableView(tableView: tableView, objectForRowAtIndexPath: indexPath)
let cls : AnyClass = self.tableView(tableView: tableView, cellClassForObject: object)
if let tempCls = cls as? PJBaseTableViewCell.Type{
return tempCls.tableView(tableView: tableView, rowHeightForObject: object,indexPath:indexPath)
}else{
return 44.0;
}
}