斗鱼swift之二次咀嚼

一、子类父类的调用问题

1、我们为什么要抽取父类呢?

当我们多个界面拥有相同的功能或者页面有相同的部分,那么我们就可以考虑抽取父类以减少我们的代码量。
BTW:我们可以多重继承,比如原始父类A只负责页面未请求导数据时动画的加载,子父类B继承父类A,拥有多个控制器相同的页面功能。然后子类C、D、E、F等类纷纷继承B,只需要根据多个界面不同的布局,重新设置。

2、重用父类的问题

a、父类方法被执行的条件:

1、父类方法在子类中被重写,在重写的方法中super.父类方法(),那么父类的方法会被执行。
2、子类没有重写父类方法,此时父类方法会被自动调用。

b、父类方法被不执行的条件:

1、子类方法重写父类方法,但是子类方法没有调用super.父类方法()。

3、子类和父类使用相同的代理

问题:

在使用子类和父类使用相同的代理的时候,我们发现会报如下错误:
错误提示:Redundant conformance of 'RecommendViewController' to protocol 'UICollectionViewDataSource'

问题分析:

Redundant:多余的,过剩的 也就是说父类已经有了,我们再用相同的代理就多余了。那子类又必须要用代理怎么办呢?例子如下:
父类A中使用了UICollectionViewDataSource、UICollectionViewDelegate,子类B中不能使用,但是我们又需要在子类中添加代理来设置不同的cell。那我们该怎么办呢?

解决办法:

我们使用继承自代理的子代理来替代父类的代理,在本例中我们就可以用继承自UICollectionViewDataSource代理的子代理UICollectionViewDelegateFlowLayout来实现,这样就避免了问题的出现。

extension RecommendViewController :  UICollectionViewDelegateFlowLayout{
    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        //~~~2、只有section == 1的参数的cell是不同的,所以子类专门区分出来,然后进行布局和显示。
        if indexPath.section == 1 {
            // 1.取出PrettyCell
            let prettyCell = collectionView.dequeueReusableCell(withReuseIdentifier: kPrettyCellID, for: indexPath) as! CollectionPrettyCell
            
            // 2.设置数据
            prettyCell.anchor = recommendVM.anchorGroups[indexPath.section].anchors[indexPath.item]
            
            return prettyCell
        } else {
            // 3、其余的和父类相同,我们直接使用父类的方法super,来显示数据。  由于index.section==1的cell比较特殊,且只有在Recommend界面才有这个cell,所以我们再子类中加载其数据,其余的section我们加载到父类中。
            //提取父类的意义:公共的方法和内容的加载我们都放到父类中,不同页面不同的界面展示,我们再在子类的上面添加相应的UI以及数据的处理,然后再调用父类的方法。
            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:我们在子类中重写创建Cell的代理方法,根据条件过滤属于子类的cell,针对父类的cell,我们通过重写调用,然后传值给父类相应的数据。
之后再reload,这样就完成了数据在父类、子类控制器上的加载。
至此完美完成了父子控件的数据加载。

二、控件的多次嵌套问题

例子:

下图就是一个经典的嵌套,UIView里面嵌套一个UICollectionView,UICollectionView创建两个cell,再在每个cell里面添加UICollectionView,然后再根据返回的数据创建多个cell,这样就完成了数据的展示。

遇到的问题:

此时相当于UIView嵌套了两层UICollectionView,那么我们怎么将事件的点击直接传递出来呢,我想到的方法是用代理,两层的代理将点击的cell的indexPatch传递给Controller,然后在Controller的代理中进行页面的跳转等操作。但是这一点需要我们设置一个代理的传递链,将数据一层层传递出来,
会比较麻烦,感觉通知传值可能更好一点,一步到位。
下面是代理传递的流程:
a、我们先设置最底层cell的代理穿参。

public protocol AmuseMenuViewCellDelegate {    
    func amuseCellDelegate(indexPath : IndexPath)
}

b、声明代理方法

 open var delegate : AmuseMenuViewCellDelegate?//设置代理方法

c、点击cell后直接调用传值的代理

//点击事件后直接调用传值的代理
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中设置代理
protocol AmuseMenuViewDelegate {
    func amuseMenuViewDelegate(indexPatch:IndexPath)
}
2、设置底层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设置数据
        setupCellDataWithCell(cell: cell, indexPath: indexPath)

        return cell
    }

3、当前UIView的代理使用底层cell的代理将值传递出来。
extension AmuseMenuView : AmuseMenuViewCellDelegate{
    func amuseCellDelegate(indexPath: IndexPath) {
        print("采集了cell的数据信息的第几个item呢:\(indexPath.row)")

    // 再传递给控制器页面
        self.delegate?.amuseMenuViewDelegate(indexPatch: indexPath)
    }
}
image.png

三、方法调用

1、设置类方法加载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、网络请求封装

1、枚举
enum MethodType {
    case get
    case post
}
2、网络请求
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.发送网络请求
        Alamofire.request(URLString, method: method, parameters: parameters).responseJSON { (response) in
            
            // 3.获取结果  guard校验
            guard let result = response.result.value else {
                print(response.result.error!)
                return
            }
            
            // 4.将结果回调出去
            finishedCallback(result)
        }
    }
}

4、GCD的网络顺序请求

func requestData(_ finishCallback : @escaping () -> ()) {
        // 1.定义参数
        let parameters = ["limit" : "4", "offset" : "0", "time" : Date.getCurrentTime()]
        
        // 2.创建Group
        let dGroup = DispatchGroup()
        
        // 3.请求第一部分推荐数据
        dGroup.enter()
        NetworkTools.requestData(.get, URLString: "http://capi.douyucdn.cn/api/v1/getbigDataRoom", parameters: ["time" : Date.getCurrentTime()]) { (result) in
            
            // 1.将result转成字典类型
            guard let resultDict = result as? [String : NSObject] else { return }
            
            // 2.根据data该key,获取数组
            guard let dataArray = resultDict["data"] as? [[String : NSObject]] else { return }
            
            // 3.遍历字典,并且转成模型对象
            // 3.1.设置组的属性
            self.bigDataGroup.tag_name = "热门"
            self.bigDataGroup.icon_name = "home_header_hot"
            
            // 3.2.获取主播数据
            for dict in dataArray {
                let anchor = AnchorModel(dict: dict)
                self.bigDataGroup.anchors.append(anchor)
            }
            
            // 3.3.离开组
            dGroup.leave()
        }
        
        // 4.请求第二部分颜值数据
        dGroup.enter()
        NetworkTools.requestData(.get, URLString: "http://capi.douyucdn.cn/api/v1/getVerticalRoom", parameters: parameters) { (result) in
            // 1.将result转成字典类型
            guard let resultDict = result as? [String : NSObject] else { return }
            
            // 2.根据data该key,获取数组
            guard let dataArray = resultDict["data"] as? [[String : NSObject]] else { return }
            
            // 3.遍历字典,并且转成模型对象
            // 3.1.设置组的属性
            self.prettyGroup.tag_name = "颜值"
            self.prettyGroup.icon_name = "home_header_phone"
            
            // 3.2.获取主播数据
            for dict in dataArray {
                let anchor = AnchorModel(dict: dict)
                self.prettyGroup.anchors.append(anchor)
            }
            
            // 3.3.离开组
            dGroup.leave()
        }
        
        // 5.请求2-12部分游戏数据
        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.所有的数据都请求到,之后进行排序
        dGroup.notify(queue: DispatchQueue.main) { 
            self.anchorGroups.insert(self.prettyGroup, at: 0)
            self.anchorGroups.insert(self.bigDataGroup, at: 0)
            
            finishCallback()
        }
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容

  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,714评论 2 59
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,097评论 1 32
  • 我们不合适做普通的朋友 我们只适合做一辈子的好朋友 和你在一起的时候 生活比梦甜
    啊猪耶阅读 145评论 0 1
  • 好歹人家是个要排队的...“网红” 离小破财又比较近.... 个人觉得他家的奶盖会比一点点的好喝 不会感觉腻 水果...
    十八线美食博主阅读 607评论 0 0
  • 1 因为公司的一些设置不合理,虽然给的title属于数据分析师,但真正所作所为似乎离一个数据分析师所能发挥的最大功...
    漢回一家阅读 357评论 0 0