通過(guò)服務(wù)器返回的數(shù)據(jù)來(lái)創(chuàng)建子控制器

??如果你有看過(guò)這個(gè)項(xiàng)目之前的代碼,肯定知道我在搭建首頁(yè)模塊的時(shí)候粉洼,是通過(guò)離線數(shù)組來(lái)創(chuàng)建子控制器的:

/// 創(chuàng)建子控制器
private func setupChildViewControllers() {
    
    // FIXME: - 從網(wǎng)絡(luò)獲取標(biāo)題的Tabs节预,然后通過(guò)JSON來(lái)設(shè)置標(biāo)題
    // 創(chuàng)建子控制器的標(biāo)題
    let titles = ["分類", "推薦", "精品", "直播", "廣播"]
    
    
    // 創(chuàng)建標(biāo)題樣式
    let titleStyle = TitleStyle()
    titleStyle.titleViewHeight = 44
    titleStyle.isScrollEnable = false  // 設(shè)置標(biāo)題下面的指示器是否可以滾動(dòng)(其實(shí)默認(rèn)為不可以滾動(dòng))
    titleStyle.selectedTextColor = UIColor(r: 246, g: 91, b: 90)  // 設(shè)置選中標(biāo)題的顏色
    titleStyle.scrollSlideBackgroundColor = UIColor(r: 246, g: 91, b: 90)  // 設(shè)置滾動(dòng)指示器的背景顏色
    titleStyle.isShowScrollSlide = true  // 需要滾動(dòng)指示器
    titleStyle.isNeedScale = false  // 需要對(duì)選中標(biāo)題進(jìn)行縮放
    titleStyle.titleFont = UIFont.systemFont(ofSize: 15)  // 設(shè)置子控制器標(biāo)題文字大小
    titleStyle.titleBackgroundColor = UIColor(r: 246, g: 246, b: 246)  // 設(shè)置子控制器標(biāo)題的背景顏色
    
    
    // 創(chuàng)建一個(gè)數(shù)組,用來(lái)存放子控制器
    var childVcs = [UIViewController]()
    
    
    // 創(chuàng)建子控制器并將其添加到childVcs數(shù)組中
    childVcs.append(CategoryViewController())  // 分類子控制器
    childVcs.append(RecommendViewController())  // 推薦子控制器
    childVcs.append(BoutiqueViewController())  // 精品子控制器
    childVcs.append(LiveViewController())  // 直播子控制器
    childVcs.append(BroadcastViewController())  // 廣播子控制器
    
    // 創(chuàng)建containerView的frame
    // - 注意:設(shè)置containerView的高度時(shí)属韧,一定不要忘記減去
    // - 狀態(tài)欄安拟、導(dǎo)航欄和tabBar的高度,否則宵喂,后面在相應(yīng)控制
    // - 器的view中添加內(nèi)容時(shí)糠赦,會(huì)導(dǎo)致有一部分內(nèi)容被tabBar給
    // - 遮擋的情況出現(xiàn)
    let containerFrame = CGRect(x: 0, y: kStatusBarHeight + kNavigationBarHeight, width: kScreenWidth, height: kScreenHeight - kStatusBarHeight - kNavigationBarHeight - kTabBarHeight - kTabBarMargin)
    
    // 調(diào)用自定義構(gòu)造函數(shù),根據(jù)實(shí)際需求創(chuàng)建合適的ContainerView對(duì)象
    let containerView = ContainerView(frame: containerFrame, titles: titles, titleStyle: titleStyle, childVcs: childVcs, parentVc: self)
    
    // 將創(chuàng)建好的ContainerView對(duì)象添加到當(dāng)前控制器的View中
    view.addSubview(containerView)
}

??也就是說(shuō)锅棕,我們事先在本地確定好子控制器的標(biāo)題和數(shù)量拙泽,然后再創(chuàng)建子控制器。這是最常規(guī)的做法裸燎,而且也可能是性能最好的做法顾瞻。但是,如果是相對(duì)于一個(gè)重度依賴網(wǎng)絡(luò)數(shù)據(jù)德绿,并且有可能需要對(duì)標(biāo)題荷荤、子控制器數(shù)量,以及子控制器選中狀態(tài)進(jìn)行動(dòng)態(tài)修改的應(yīng)用來(lái)說(shuō)移稳,這種做法其實(shí)并不靈活蕴纳。好的做法是,通過(guò)服務(wù)器返回的數(shù)據(jù)來(lái)確定標(biāo)題及其數(shù)量个粱,這樣我們就可以靈活的修改數(shù)據(jù)古毛,而不用重新上架應(yīng)用了。

通過(guò)網(wǎng)絡(luò)數(shù)據(jù)來(lái)確定子控制器標(biāo)題.png

??接下來(lái)都许,我們所要做的就是稻薇,發(fā)送網(wǎng)絡(luò)數(shù)據(jù),然后對(duì)服務(wù)器返回的數(shù)據(jù)進(jìn)行解析梭稚,最后再將解析完成的標(biāo)題存放到數(shù)組中颖低,之后再通過(guò)這個(gè)數(shù)組來(lái)創(chuàng)建子控制器及其標(biāo)題。首先我們來(lái)看一下如何發(fā)送網(wǎng)絡(luò)數(shù)據(jù):

/// RequestURL
private let kRequestURL = "http://recpage.c.qingting.fm/v3/navbar"

class NavBarViewModel: NSObject {
    
    /// 用于存儲(chǔ)轉(zhuǎn)換完成的模型數(shù)據(jù)
    lazy var navBarModelArray = [NavBarModel]()
}


extension NavBarViewModel {

    /// 請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)并將其轉(zhuǎn)換為模型
    func requestData(completionHandler: @escaping () -> ()) {
        
        // 通過(guò)Alamofrie來(lái)發(fā)送網(wǎng)絡(luò)請(qǐng)求
        NetworkTools.shareTools.requestData(kRequestURL, .get, parameters: ["wt": "json", "v": "6.0.4", "deviceid": "093e8b7e24c02246fe92373727e4a92c", "phonetype": "iOS", "osv": "11.1.1", "device": "iPhone", "pkg": "com.Qting.QTTour"]) { (result) in
            
            /// 將JSON數(shù)據(jù)轉(zhuǎn)成字典
            guard let resultDict = result as? [String: Any] else { return }
            
            /// 根據(jù)字典中的關(guān)鍵字data取出字典中的數(shù)組數(shù)據(jù)
            guard let resultArray = resultDict["data"] as? [[String: Any]] else { return }
            
            /// 遍歷數(shù)組resultArray弧烤,取出它里面的字典
            for dict in resultArray {
                
                // 將字典轉(zhuǎn)為模型
                let item = NavBarModel(dict: dict)
                
                // 將轉(zhuǎn)換完成的模型存儲(chǔ)起來(lái)
                self.navBarModelArray.append(item)
            }
            
            // 數(shù)據(jù)回調(diào)
            completionHandler()
        }
    }
}

??在將網(wǎng)絡(luò)數(shù)據(jù)轉(zhuǎn)成模型的過(guò)程中忱屑,我們沒(méi)有借助任何的第三方框架,是直接通過(guò)KVC來(lái)完成的暇昂。在設(shè)計(jì)模型文件的時(shí)候莺戒,需要對(duì)服務(wù)器返回的JSON數(shù)據(jù)進(jìn)行分析:

JSON數(shù)據(jù)分析.png

??上面返回的這個(gè)JSON數(shù)據(jù)比較簡(jiǎn)單,基本上沒(méi)有什么嵌套急波,并且唯一的一個(gè)嵌套字典link沒(méi)什么用从铲,我們可以不用解析。另外澄暮,需要特別強(qiáng)調(diào)的是名段,在Swift 4中利用KVC進(jìn)行字典轉(zhuǎn)模型的時(shí)候阱扬,一定不要忘記在類的定義前面加上屬性關(guān)鍵字@objcMembers,否則鍵值匹配會(huì)失效:

@objcMembers
class NavBarModel: NSObject {
    
    // MARK: - 服務(wù)器返回的模型屬性
    
    /// 標(biāo)題
    var title: String = ""
    
    /// urlScheme
    var urlScheme: String = ""
    
    /// 當(dāng)前子控制器是否被選中
    var current: Bool = false
    
    // MARK: - 自定義構(gòu)造函數(shù)
    
    /// 將字典轉(zhuǎn)為模型
    init(dict: [String: Any]) {
        super.init()
        
        // 利用KVC將字典轉(zhuǎn)為模型
        setValuesForKeys(dict)
    }
    
    override func setValue(_ value: Any?, forUndefinedKey key: String) { }
}

??網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求和字典轉(zhuǎn)模型的工作都做完了之后伸辟,再回到控制器中麻惶,修改創(chuàng)建子控制器的代碼。當(dāng)然信夫,前面一定要聲明一個(gè)viewModel屬性窃蹋,用來(lái)請(qǐng)求數(shù)據(jù)。有了數(shù)據(jù)之后静稻,就可以從模型性取出標(biāo)題了警没,然后就可以通過(guò)網(wǎng)絡(luò)數(shù)據(jù)來(lái)創(chuàng)建子控制器及其標(biāo)題了:

/// 創(chuàng)建子控制器
private func setupChildViewControllers() {
    
    // 發(fā)送網(wǎng)絡(luò)請(qǐng)求,獲取網(wǎng)絡(luò)上的標(biāo)題
    navBarViewModel.requestData {
        
        // 從模型中取出標(biāo)題振湾,并且將其存放到一個(gè)數(shù)組中
        let titles = self.navBarViewModel.navBarModelArray.map({ $0.title })
        
        // 創(chuàng)建標(biāo)題樣式
        let titleStyle = TitleStyle()
        titleStyle.titleViewHeight = 44
        titleStyle.isScrollEnable = false  // 設(shè)置標(biāo)題下面的指示器是否可以滾動(dòng)(其實(shí)默認(rèn)為不可以滾動(dòng))
        titleStyle.selectedTextColor = UIColor(r: 246, g: 91, b: 90)  // 設(shè)置選中標(biāo)題的顏色
        titleStyle.scrollSlideBackgroundColor = UIColor(r: 246, g: 91, b: 90)  // 設(shè)置滾動(dòng)指示器的背景顏色
        titleStyle.isShowScrollSlide = true  // 需要滾動(dòng)指示器
        titleStyle.isNeedScale = false  // 需要對(duì)選中標(biāo)題進(jìn)行縮放
        titleStyle.titleFont = UIFont.systemFont(ofSize: 15)  // 設(shè)置子控制器標(biāo)題文字大小
        titleStyle.titleBackgroundColor = UIColor(r: 246, g: 246, b: 246)  // 設(shè)置子控制器標(biāo)題的背景顏色
        
        
        // 創(chuàng)建一個(gè)數(shù)組杀迹,用來(lái)存放子控制器
        var childVcs = [UIViewController]()
        
        
        // 創(chuàng)建子控制器并將其添加到childVcs數(shù)組中
        childVcs.append(CategoryViewController())  // 分類子控制器
        childVcs.append(RecommendViewController())  // 推薦子控制器
        childVcs.append(BoutiqueViewController())  // 精品子控制器
        childVcs.append(LiveViewController())  // 直播子控制器
        childVcs.append(BroadcastViewController())  // 廣播子控制器
        
        
        // 創(chuàng)建containerView的frame
        // - 注意:設(shè)置containerView的高度時(shí),一定不要忘記減去
        // - 狀態(tài)欄恰梢、導(dǎo)航欄和tabBar的高度佛南,否則,后面在相應(yīng)控制
        // - 器的view中添加內(nèi)容時(shí)嵌言,會(huì)導(dǎo)致有一部分內(nèi)容被tabBar給
        // - 遮擋的情況出現(xiàn)
        let containerFrame = CGRect(x: 0, y: kStatusBarHeight + kNavigationBarHeight, width: kScreenWidth, height: kScreenHeight - kStatusBarHeight - kNavigationBarHeight - kTabBarHeight - kTabBarMargin)
        
        // 調(diào)用自定義構(gòu)造函數(shù)嗅回,根據(jù)實(shí)際需求創(chuàng)建合適的ContainerView對(duì)象
        let containerView = ContainerView(frame: containerFrame, titles: titles, titleStyle: titleStyle, childVcs: childVcs, parentVc: self)
        
        // 將創(chuàng)建好的ContainerView對(duì)象添加到當(dāng)前控制器的View中
        self.view.addSubview(containerView)
    }
}

??原本只是一行代碼的事情,而我們卻多搞了兩個(gè)文件摧茴,一個(gè)NavBarViewModel文件绵载,以及一個(gè)NavBarModel文件,并且還多寫了好多代碼苛白,這么做絕對(duì)不是為了裝逼娃豹,而是有著非常明確的現(xiàn)實(shí)需求——不必通過(guò)重新提交應(yīng)用到App Store就可以動(dòng)態(tài)的修改子控制器的標(biāo)題及其數(shù)量。當(dāng)然购裙,這個(gè)也不是隨便就能修改的懂版,前提是項(xiàng)目中有與之對(duì)應(yīng)的類。項(xiàng)目代碼參見(jiàn)QTRadio躏率。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末躯畴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子薇芝,更是在濱河造成了極大的恐慌蓬抄,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夯到,死亡現(xiàn)場(chǎng)離奇詭異嚷缭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門阅爽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)路幸,“玉大人,你說(shuō)我怎么就攤上這事优床∪芭猓” “怎么了誓焦?”我有些...
    開(kāi)封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵胆敞,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我帆吻,道長(zhǎng)掖棉,這世上最難降的妖魔是什么拐袜? 我笑而不...
    開(kāi)封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮观话,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘越平。我一直安慰自己频蛔,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布秦叛。 她就那樣靜靜地躺著晦溪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挣跋。 梳的紋絲不亂的頭發(fā)上三圆,一...
    開(kāi)封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音避咆,去河邊找鬼舟肉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛查库,可吹牛的內(nèi)容都是我干的路媚。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼樊销,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼整慎!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起现柠,我...
    開(kāi)封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤院领,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后够吩,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體比然,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年周循,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了强法。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片万俗。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖饮怯,靈堂內(nèi)的尸體忽然破棺而出闰歪,到底是詐尸還是另有隱情,我是刑警寧澤蓖墅,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布库倘,位于F島的核電站,受9級(jí)特大地震影響论矾,放射性物質(zhì)發(fā)生泄漏教翩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一贪壳、第九天 我趴在偏房一處隱蔽的房頂上張望饱亿。 院中可真熱鬧,春花似錦闰靴、人聲如沸彪笼。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)配猫。三九已至,卻和暖如春膘掰,著一層夾襖步出監(jiān)牢的瞬間章姓,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工识埋, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凡伊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓窒舟,卻偏偏與公主長(zhǎng)得像系忙,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子惠豺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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