從頭開始swift2.1 仿搜材通項(xiàng)目(八) 制定通用的Controller規(guī)則

我們知道果善,ViewController加載完成必調(diào)用viewDidLoad方法,在此方法里我們可以做一些加載完成之后的事情嫡锌,但在團(tuán)隊(duì)開發(fā)中,每個(gè)人的思路都可能是不一樣的琳钉,有的喜歡命名方法(或者叫函數(shù))叫initXXXX()势木,也有的喜歡叫g(shù)oXXXX(),有的甚至直接把一大段代碼寫到viewDidLoad中歌懒,且不說別人很難維護(hù)他的代碼啦桌,過了一段時(shí)間后,估計(jì)連他自己也不明白當(dāng)時(shí)寫代碼的思路了及皂。所以甫男,無規(guī)矩不成方圓,我們今天來制定一些Controller的規(guī)則验烧,即方便自己板驳,也方便你的隊(duì)友。

完成封裝后UITableViewController的編碼:

import UIKit

class PriceListController: BaseTableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        initWithParams("PriceCell", heightForRowAtIndexPath: 70, canLoadRefresh: true, canLoadMore: true)
    }
    
    override func loadData() {
        //請求地址 借用百度糯米來演示一下
        let url = "http://apis.baidu.com/baidunuomi/openapi/searchdeals"

        var params:[String:AnyObject] = Dictionary()
        params.updateValue("800010000", forKey: "city_id")//城市ID 成都
        params.updateValue("\(page)", forKey: "page")
        params.updateValue("\(pageSize)", forKey: "page_size")
        
        HMRequest<PriceDomain>.get(url, params: params) { (price, error) -> () in
            //需要對數(shù)據(jù)正確性進(jìn)行判斷碍拆,演示時(shí)我省略了這一步
            //請求數(shù)據(jù)成功后調(diào)用
            if self.action == LoadAction.loadNew {
                self.dataList.removeAll()
            }
            
            for data in (price?.data?.deals)! {
                self.dataList.append(data)
            }

            self.loadCompleted()
        }
    }
}

完成封裝后效果圖


首先在Library目錄下新建一個(gè)Base的文件夾若治,然后拖進(jìn)Xcode中慨蓝,在其下面創(chuàng)建一個(gè)BaseViewController。


這里寫圖片描述

先對其添加一些簡單的方法端幼,后面我們在使用過程中可以根據(jù)自己的需要進(jìn)行修改礼烈。

/// 通用ViewController類
class BaseViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if checkParams() {
            loadData()
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    
    /**
     檢查調(diào)用本類必需傳遞的參數(shù)條件是否滿足
     默認(rèn)返回true,在需要的類中重寫此方法即可
     
     - returns: true為滿足
     */
    func checkParams() -> Bool {
        return true
    }
    
    /**
     加載數(shù)據(jù)婆跑,請求接口或者讀取本地
     子類可不重寫此熬,默認(rèn)調(diào)用初始化界面方法
     */
    func loadData(){
        initUI()
    }
    
    /**
     初始化界面,在這里可以分為幾個(gè)方法函數(shù)來調(diào)用
     */
    func initUI(){}
    
    
}

再添加一個(gè)通用的BaseTableViewController滑进,添加之前先到Podfile中增加XWSwiftRefresh的上下拉刷新:

pod 'XWSwiftRefresh' #上下拉刷新 https://github.com/boyXiong/XWSwiftRefresh

再創(chuàng)建一個(gè)BaseTableViewCell犀忱,在BaseTableViewController中會(huì)用到:

class BaseTableViewCell: UITableViewCell {

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
    
    /**
     設(shè)置展示內(nèi)容
     
     - parameter tableView: tableView
     - parameter indexPath: indexPath
     - parameter dataList:  dataList
     */
    func setContent(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, dataList:[HMSerializable] ){
        //do something
    }

}

下面是對BaseTableViewController的編碼:

import UIKit
import XWSwiftRefresh

enum LoadAction{
    case loadNew
    case LoadMore
}

class BaseTableViewController: BaseViewController,UITableViewDelegate,UITableViewDataSource {

    /// 默認(rèn)的CellIdentifier
    var identifier:String = "Cell"
    
    /// 默認(rèn)行高
    var heightForRowAtIndexPath:CGFloat = 100
    
    var tableView:UITableView!
    
    /// 動(dòng)作標(biāo)識(shí)
    var action:LoadAction = .loadNew
    
    /// 當(dāng)前頁,如果后臺(tái)是從0開始那這里就修改為0
    var page:Int = 1
    
    /// 每頁加載多少條
    var pageSize:Int = 10
    
    /// 數(shù)據(jù)源集合
    var dataList:[HMSerializable] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //如果布局中沒有tableView郊供,則默認(rèn)通過代碼創(chuàng)建一個(gè)全屏的tableView
        if tableView == nil {
            tableView =  UITableView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height - (self.navigationController?.navigationBar.frame.height)! - UIApplication.sharedApplication().statusBarFrame.height), style: UITableViewStyle.Plain)
            self.view.addSubview(tableView)
        }
        
        tableView.delegate = self
        tableView.dataSource = self
    }
    
    /**
     初始化TableView配置
     
     - parameter nibName:                 自定義Cell的文件名
     - parameter heightForRowAtIndexPath: 行高
     - parameter canLoadRefresh:          是否支持下拉刷新
     - parameter canLoadMore:             是否支持上拉加載

     */
    func initWithParams(nibName:String, heightForRowAtIndexPath:CGFloat, canLoadRefresh:Bool, canLoadMore:Bool){
        
        tableView.registerNib(UINib(nibName: nibName, bundle: nil), forCellReuseIdentifier:identifier)
        
        self.heightForRowAtIndexPath = heightForRowAtIndexPath
        
        if canLoadRefresh {
            //添加下拉刷新
            tableView.headerView = XWRefreshNormalHeader(target: self, action: "loadRefresh")
        }
        
        if canLoadMore {
            //添加上拉加載
            tableView.footerView = XWRefreshAutoNormalFooter(target: self, action: "loadMore")
        }
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

     func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

     func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataList.count
    }
    
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return heightForRowAtIndexPath
    }


     func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) as! BaseTableViewCell

        cell.setContent(tableView, cellForRowAtIndexPath: indexPath, dataList: dataList)

        return cell
    }
    
    /**
     執(zhí)行刷新
     */
    func loadRefresh(){
        action = .loadNew
        page = 1
        loadData()
    }
    
    /**
     執(zhí)行加載更多
     */
    func loadMore(){
        action = .LoadMore
        page++
        loadData()
    }
    
    /**
     加載完成
     */
    func loadCompleted(){
        if action == .loadNew {
            tableView.headerView?.endRefreshing()
        } else {
            tableView.footerView?.endRefreshing()
        }
        tableView.reloadData()
    }

}

現(xiàn)在我們寫好了兩個(gè)通用的Base類峡碉,如何使用呢近哟?我們先演示一下BaseViewController驮审。還記得之前寫的HomeController嗎?


這里寫圖片描述

修改HomeController繼承自BaseViewController吉执,我們應(yīng)該明白疯淫,BaseViewController的執(zhí)行順序是 checkParams() -> loadData() -> initUI() ,這里我們不需要傳遞任何參數(shù)戳玫,checkParams的方法可以不用重寫熙掺,那我們就來重寫一下這個(gè)類:



現(xiàn)在看這個(gè)步驟,是不是清晰多了呢咕宿?我們再增加一個(gè)列表界面來演示BaseTableViewController:
創(chuàng)建一個(gè)PriceCell簡單布局并連線:

通過API調(diào)試得到接口返回?cái)?shù)據(jù)結(jié)構(gòu)如下:



根據(jù)json編寫模型實(shí)體類币绩,實(shí)際開發(fā)中可以使用ESJsonFormat根據(jù)json自動(dòng)生成對應(yīng)字段,但現(xiàn)在我們演示只需要幾個(gè)字段就可以:
struct PriceDomain: HMSerializable ,HMConvertible{
    
    var error: Int = 0
    
    var msg: Int = 0
    
    var data: PriceData?
    
    static func convertFromData(data: String!) -> (PriceDomain, NSError?) {
        var hm : PriceDomain?
        hm <-- data
        return (hm!,nil)
    }
    
    init(data: [String: AnyObject]) {
        error <-- data["error"]
        msg <-- data["msg"]
        self.data <-- data["data"]
    }
    
    struct PriceData: HMSerializable {
        var total: String? 
        var deals: [PriceDeal]? 
        
        init(data: [String: AnyObject]) {
            total <-- data["total"]
            deals <-- data["deals"]
        }
        
        //可以只取我們需要的字段府阀,不需要全部解析
        struct PriceDeal: HMSerializable {
            var image: String?
            var title: String?
            var description: String?
            
            init(data: [String: AnyObject]) {
                image <-- data["image"]
                title <-- data["title"]
                description <-- data["description"]
            }
        }
    }
    
}

接著是PriceCell的實(shí)現(xiàn):

class PriceCell: BaseTableViewCell {

    @IBOutlet weak var iv_Photo: UIImageView!
    @IBOutlet weak var lbl_Title: UILabel!
    @IBOutlet weak var lbl_Desc: UILabel!
    
    override func setContent(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, dataList:[HMSerializable] ){
        let data = dataList[indexPath.row] as! PriceDomain.PriceData.PriceDeal
        lbl_Title.text = data.title
        lbl_Desc.text = data.description
        iv_Photo.kf_setImageWithURL(NSURL(string: data.image!)!)
    }

}

最后是PriceListController的實(shí)現(xiàn):

class PriceListController: BaseTableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        initWithParams("PriceCell", heightForRowAtIndexPath: 70, canLoadRefresh: true, canLoadMore: true)
    }
    
    override func loadData() {
        //請求地址 借用百度糯米來演示一下
        let url = "http://apis.baidu.com/baidunuomi/openapi/searchdeals"

        var params:[String:AnyObject] = Dictionary()
        params.updateValue("800010000", forKey: "city_id")//城市ID 成都
        params.updateValue("\(page)", forKey: "page")
        params.updateValue("\(pageSize)", forKey: "page_size")
        
        HMRequest<PriceDomain>.get(url, params: params) { (price, error) -> () in
            //需要對數(shù)據(jù)正確性進(jìn)行判斷缆镣,演示時(shí)我省略了這一步
            //請求數(shù)據(jù)成功后調(diào)用
            if self.action == LoadAction.loadNew {
                self.dataList.removeAll()
            }
            
            for data in (price?.data?.deals)! {
                self.dataList.append(data)
            }

            self.loadCompleted()
        }
    }
}

運(yùn)行看看效果:


這樣,我們就達(dá)成了兩個(gè)BaseController的封裝试浙,尤其是BaseTableViewController董瞻,我們只需要在VC中調(diào)用兩個(gè)方法,initWithParams和loadData就可以達(dá)到自定義Cell及上下拉刷新加載等效果田巴,是不是很酷呢钠糊?
Git地址:https://github.com/bxcx/sctong
本節(jié)分支:https://github.com/bxcx/sctong/tree/7th_BaseController

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市壹哺,隨后出現(xiàn)的幾起案子抄伍,更是在濱河造成了極大的恐慌,老刑警劉巖管宵,帶你破解...
    沈念sama閱讀 223,126評論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逝慧,死亡現(xiàn)場離奇詭異昔脯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)笛臣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評論 3 400
  • 文/潘曉璐 我一進(jìn)店門云稚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人沈堡,你說我怎么就攤上這事静陈。” “怎么了诞丽?”我有些...
    開封第一講書人閱讀 169,941評論 0 366
  • 文/不壞的土叔 我叫張陵鲸拥,是天一觀的道長。 經(jīng)常有香客問我僧免,道長刑赶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,294評論 1 300
  • 正文 為了忘掉前任懂衩,我火速辦了婚禮撞叨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浊洞。我一直安慰自己牵敷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,295評論 6 398
  • 文/花漫 我一把揭開白布法希。 她就那樣靜靜地躺著枷餐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪苫亦。 梳的紋絲不亂的頭發(fā)上毛肋,一...
    開封第一講書人閱讀 52,874評論 1 314
  • 那天,我揣著相機(jī)與錄音屋剑,去河邊找鬼润匙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛饼丘,可吹牛的內(nèi)容都是我干的趁桃。 我是一名探鬼主播,決...
    沈念sama閱讀 41,285評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼肄鸽,長吁一口氣:“原來是場噩夢啊……” “哼卫病!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起典徘,我...
    開封第一講書人閱讀 40,249評論 0 277
  • 序言:老撾萬榮一對情侶失蹤蟀苛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后逮诲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體帜平,經(jīng)...
    沈念sama閱讀 46,760評論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡幽告,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,840評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了裆甩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冗锁。...
    茶點(diǎn)故事閱讀 40,973評論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嗤栓,靈堂內(nèi)的尸體忽然破棺而出冻河,到底是詐尸還是另有隱情,我是刑警寧澤茉帅,帶...
    沈念sama閱讀 36,631評論 5 351
  • 正文 年R本政府宣布叨叙,位于F島的核電站,受9級特大地震影響堪澎,放射性物質(zhì)發(fā)生泄漏擂错。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,315評論 3 336
  • 文/蒙蒙 一樱蛤、第九天 我趴在偏房一處隱蔽的房頂上張望钮呀。 院中可真熱鬧,春花似錦刹悴、人聲如沸行楞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,797評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至形用,卻和暖如春就轧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背田度。 一陣腳步聲響...
    開封第一講書人閱讀 33,926評論 1 275
  • 我被黑心中介騙來泰國打工妒御, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人镇饺。 一個(gè)月前我還...
    沈念sama閱讀 49,431評論 3 379
  • 正文 我出身青樓乎莉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親奸笤。 傳聞我的和親對象是個(gè)殘疾皇子惋啃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,982評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件监右、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,128評論 4 61
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,348評論 25 707
  • 本節(jié)是仿搜材通項(xiàng)目的最后一節(jié)了边灭,前面我們記錄了主流框架(Tabbed)的搭建,第三方SDK(百度地圖)的集成健盒,使用...
    a_mean閱讀 780評論 7 8
  • 想讓自己停幾天 你想留言什么就說什么吧绒瘦? 我最近的狀態(tài)和老師一樣称簿,極度想把手頭的事做好,總是提不起精神惰帽,不會(huì)是同頻吧憨降!
    MASTERJIANG閱讀 188評論 0 0
  • 這幾天心里有些發(fā)悶,恰逢兄弟天團(tuán)一聲招喚背起行囊就出了門该酗,說走就走的旅行注定會(huì)有各種不可預(yù)期券册,到達(dá)目的地已至下午四...
    牛朋利閱讀 165評論 0 0