一、子類父類的調(diào)用問題
1轨帜、我們?yōu)槭裁匆槿「割惸兀?/h4>
當我們多個界面擁有相同的功能或者頁面有相同的部分魄咕,那么我們就可以考慮抽取父類以減少我們的代碼量。
BTW:我們可以多重繼承蚌父,比如原始父類A只負責頁面未請求導(dǎo)數(shù)據(jù)時動畫的加載哮兰,子父類B繼承父類A,擁有多個控制器相同的頁面功能苟弛。然后子類C喝滞、D、E膏秫、F等類紛紛繼承B右遭,只需要根據(jù)多個界面不同的布局,重新設(shè)置缤削。
2窘哈、重用父類的問題
a、父類方法被執(zhí)行的條件:
1亭敢、父類方法在子類中被重寫滚婉,在重寫的方法中super.父類方法(),那么父類的方法會被執(zhí)行吨拗。
2满哪、子類沒有重寫父類方法婿斥,此時父類方法會被自動調(diào)用。
b哨鸭、父類方法被不執(zhí)行的條件:
1民宿、子類方法重寫父類方法,但是子類方法沒有調(diào)用super.父類方法()像鸡。
3活鹰、子類和父類使用相同的代理
問題:
在使用子類和父類使用相同的代理的時候,我們發(fā)現(xiàn)會報如下錯誤:
錯誤提示:Redundant conformance of 'RecommendViewController' to protocol 'UICollectionViewDataSource'
問題分析:
Redundant:多余的只估,過剩的 也就是說父類已經(jīng)有了志群,我們再用相同的代理就多余了。那子類又必須要用代理怎么辦呢蛔钙?例子如下:
父類A中使用了UICollectionViewDataSource锌云、UICollectionViewDelegate,子類B中不能使用吁脱,但是我們又需要在子類中添加代理來設(shè)置不同的cell桑涎。那我們該怎么辦呢?
解決辦法:
我們使用繼承自代理的子代理來替代父類的代理兼贡,在本例中我們就可以用繼承自UICollectionViewDataSource代理的子代理UICollectionViewDelegateFlowLayout來實現(xiàn)攻冷,這樣就避免了問題的出現(xiàn)。
extension RecommendViewController : UICollectionViewDelegateFlowLayout{
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//~~~2遍希、只有section == 1的參數(shù)的cell是不同的等曼,所以子類專門區(qū)分出來,然后進行布局和顯示凿蒜。
if indexPath.section == 1 {
// 1.取出PrettyCell
let prettyCell = collectionView.dequeueReusableCell(withReuseIdentifier: kPrettyCellID, for: indexPath) as! CollectionPrettyCell
// 2.設(shè)置數(shù)據(jù)
prettyCell.anchor = recommendVM.anchorGroups[indexPath.section].anchors[indexPath.item]
return prettyCell
} else {
// 3禁谦、其余的和父類相同,我們直接使用父類的方法super篙程,來顯示數(shù)據(jù)枷畏。 由于index.section==1的cell比較特殊,且只有在Recommend界面才有這個cell,所以我們再子類中加載其數(shù)據(jù)虱饿,其余的section我們加載到父類中拥诡。
//提取父類的意義:公共的方法和內(nèi)容的加載我們都放到父類中,不同頁面不同的界面展示氮发,我們再在子類的上面添加相應(yīng)的UI以及數(shù)據(jù)的處理渴肉,然后再調(diào)用父類的方法。
print("打印的傳給父類的索引為\(indexPath.section)")
return super.collectionView(collectionView, cellForItemAt: indexPath)
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath.section == 1 {
return CGSize(width: kNormalItemW, height: kPrettyItemH)
}
return CGSize(width: kNormalItemW, height: kNormalItemH)
}
}
BTW:我們在子類中重寫創(chuàng)建Cell的代理方法爽冕,根據(jù)條件過濾屬于子類的cell仇祭,針對父類的cell,我們通過重寫調(diào)用颈畸,然后傳值給父類相應(yīng)的數(shù)據(jù)乌奇。
之后再reload没讲,這樣就完成了數(shù)據(jù)在父類、子類控制器上的加載礁苗。
至此完美完成了父子控件的數(shù)據(jù)加載爬凑。
二、控件的多次嵌套問題
例子:
下圖就是一個經(jīng)典的嵌套试伙,UIView里面嵌套一個UICollectionView嘁信,UICollectionView創(chuàng)建兩個cell,再在每個cell里面添加UICollectionView疏叨,然后再根據(jù)返回的數(shù)據(jù)創(chuàng)建多個cell,這樣就完成了數(shù)據(jù)的展示卦溢。
遇到的問題:
此時相當于UIView嵌套了兩層UICollectionView,那么我們怎么將事件的點擊直接傳遞出來呢誓军,我想到的方法是用代理捷雕,兩層的代理將點擊的cell的indexPatch傳遞給Controller救巷,然后在Controller的代理中進行頁面的跳轉(zhuǎn)等操作。但是這一點需要我們設(shè)置一個代理的傳遞鏈精盅,將數(shù)據(jù)一層層傳遞出來叹俏,
會比較麻煩粘驰,感覺通知傳值可能更好一點蝌数,一步到位亭珍。
下面是代理傳遞的流程:
a、我們先設(shè)置最底層cell的代理穿參。
public protocol AmuseMenuViewCellDelegate {
func amuseCellDelegate(indexPath : IndexPath)
}
b粱侣、聲明代理方法
open var delegate : AmuseMenuViewCellDelegate?//設(shè)置代理方法
c、點擊cell后直接調(diào)用傳值的代理
//點擊事件后直接調(diào)用傳值的代理
extension AmuseMenuViewCell : UICollectionViewDelegate{
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("點擊了collectionView中的cell中的collectionview中的cell:\(indexPath.row)")
self.delegate?.amuseCellDelegate(indexPath: indexPath)
}
}
d、在當前UIView的collectionView的cell中添加代理接收到穿參诱担。
1丐箩、View中設(shè)置代理
protocol AmuseMenuViewDelegate {
func amuseMenuViewDelegate(indexPatch:IndexPath)
}
2、設(shè)置底層cell的接收代理
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// 1.取出cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kMenuCellID, for: indexPath) as! AmuseMenuViewCell
cell.delegate = self
// 2.給cell設(shè)置數(shù)據(jù)
setupCellDataWithCell(cell: cell, indexPath: indexPath)
return cell
}
3、當前UIView的代理使用底層cell的代理將值傳遞出來挑秉。
extension AmuseMenuView : AmuseMenuViewCellDelegate{
func amuseCellDelegate(indexPath: IndexPath) {
print("采集了cell的數(shù)據(jù)信息的第幾個item呢:\(indexPath.row)")
// 再傳遞給控制器頁面
self.delegate?.amuseMenuViewDelegate(indexPatch: indexPath)
}
}
三立哑、方法調(diào)用
1铛绰、設(shè)置類方法加載nib的View:
extension AmuseMenuView {
class func amuseMenuView() -> AmuseMenuView {
return Bundle.main.loadNibNamed("AmuseMenuView", owner: nil, options: nil)?.first as! AmuseMenuView
}
}
2、懶加載
// MAR:- 游戲條敢会,加載多個游戲这嚣。
fileprivate lazy var gameView : RecommendGameView = {
let gameView = RecommendGameView.recommendGameView()
gameView.frame = CGRect(x: 0, y: -kGameViewH, width: kScreenW, height: kGameViewH)
return gameView
}()
3、網(wǎng)絡(luò)請求封裝
1膳汪、枚舉
enum MethodType {
case get
case post
}
2、網(wǎng)絡(luò)請求
class NetworkTools {
class func requestData(_ type : MethodType, URLString : String, parameters : [String : Any]? = nil, finishedCallback : @escaping (_ result : Any) -> ()) {
// 1.獲取類型
let method = type == .get ? HTTPMethod.get : HTTPMethod.post
// 2.發(fā)送網(wǎng)絡(luò)請求
Alamofire.request(URLString, method: method, parameters: parameters).responseJSON { (response) in
// 3.獲取結(jié)果 guard校驗
guard let result = response.result.value else {
print(response.result.error!)
return
}
// 4.將結(jié)果回調(diào)出去
finishedCallback(result)
}
}
}
4鼓蜒、GCD的網(wǎng)絡(luò)順序請求
func requestData(_ finishCallback : @escaping () -> ()) {
// 1.定義參數(shù)
let parameters = ["limit" : "4", "offset" : "0", "time" : Date.getCurrentTime()]
// 2.創(chuàng)建Group
let dGroup = DispatchGroup()
// 3.請求第一部分推薦數(shù)據(jù)
dGroup.enter()
NetworkTools.requestData(.get, URLString: "http://capi.douyucdn.cn/api/v1/getbigDataRoom", parameters: ["time" : Date.getCurrentTime()]) { (result) in
// 1.將result轉(zhuǎn)成字典類型
guard let resultDict = result as? [String : NSObject] else { return }
// 2.根據(jù)data該key,獲取數(shù)組
guard let dataArray = resultDict["data"] as? [[String : NSObject]] else { return }
// 3.遍歷字典,并且轉(zhuǎn)成模型對象
// 3.1.設(shè)置組的屬性
self.bigDataGroup.tag_name = "熱門"
self.bigDataGroup.icon_name = "home_header_hot"
// 3.2.獲取主播數(shù)據(jù)
for dict in dataArray {
let anchor = AnchorModel(dict: dict)
self.bigDataGroup.anchors.append(anchor)
}
// 3.3.離開組
dGroup.leave()
}
// 4.請求第二部分顏值數(shù)據(jù)
dGroup.enter()
NetworkTools.requestData(.get, URLString: "http://capi.douyucdn.cn/api/v1/getVerticalRoom", parameters: parameters) { (result) in
// 1.將result轉(zhuǎn)成字典類型
guard let resultDict = result as? [String : NSObject] else { return }
// 2.根據(jù)data該key,獲取數(shù)組
guard let dataArray = resultDict["data"] as? [[String : NSObject]] else { return }
// 3.遍歷字典,并且轉(zhuǎn)成模型對象
// 3.1.設(shè)置組的屬性
self.prettyGroup.tag_name = "顏值"
self.prettyGroup.icon_name = "home_header_phone"
// 3.2.獲取主播數(shù)據(jù)
for dict in dataArray {
let anchor = AnchorModel(dict: dict)
self.prettyGroup.anchors.append(anchor)
}
// 3.3.離開組
dGroup.leave()
}
// 5.請求2-12部分游戲數(shù)據(jù)
dGroup.enter()
// http://capi.douyucdn.cn/api/v1/getHotCate?limit=4&offset=0&time=1474252024
loadAnchorData(isGroupData: true, URLString: "http://capi.douyucdn.cn/api/v1/getHotCate", parameters: parameters) {
dGroup.leave()
}
// 6.所有的數(shù)據(jù)都請求到,之后進行排序
dGroup.notify(queue: DispatchQueue.main) {
self.anchorGroups.insert(self.prettyGroup, at: 0)
self.anchorGroups.insert(self.bigDataGroup, at: 0)
finishCallback()
}
}