JFDouYu-Swift(二)

今天 先分享下MVVM

image.png

上图描述了MVVM一个基本结构,看到了什么,是不是发现比MVC架构中多了一个ViewModel,没错,就是这个ViewModel,他是MVVM相对于MVC改进的核心思想。在开发过程中,由于需求的变更或添加,项目的复杂度越来越高,代码量越来越大,此时我们会发现MVC维护起来有些吃力,首先被人吐槽的最多的就是MVC的简写变成了Massive-View-Controller(意为沉重的Controller)
由于Controller主要用来处理各种逻辑和数据转化,复杂业务逻辑界面的Controller非常庞大,维护困难,所以有人想到把Controller的数据和逻辑处理部分从中抽离出来,用一个专门的对象去管理,这个对象就是ViewModel,是Model和Controller之间的一座桥梁。当人们去尝试这种方式时,发现Controller中的代码变得非常少,变得易于测试和维护,只需要Controller和ViewModel做数据绑定即可,这也就催生了MVVM的热潮。

MVVM值得用么?

个人非常推荐使用,并且可以直接在你现有的MVC基础上进行扩展,我们首先来看下优缺点
优点:
1.Controller清晰简洁: ViewModel分离了大部分Controller代码,更加清晰和容易维护。

2.方便测试:开发中大部分Bug来至于逻辑处理,由于ViewModel分离了许多逻辑,可以对ViewModel构造单元测试。
3.开发解耦(举两个例子):
a.一人负责逻辑实现、另一人负责UI实现;
b.敏捷开发时,会发经常发不是等后端做好了接口我们再去开发,不过在没有接口的情况下通常我们可以把Controller和View完成。
缺点:
1.看起来代码会比MVC多点
2.需要对每个Controller实现绑定,如果处理不好,反而会有一种“画虎不成反类犬”的感觉

总结

在我实际使用过程中,MVVM写出的代码量并不比MVC的少,有时反而还会多点,毕竟多了一个数据绑定过程,但逻辑会清晰很多,对于多人开发的团队,还是有不少优势的,缺点和优点相比不值一提,总之推荐使用

[图片上传中...(image.png-7c4251-1600679073207-0)]

接下来举个例子

定义一个ViewModel

/// 可以不继承 : NSObject 使这个 JFGameViewModel 更轻量级
class JFGameViewModel{
    //懒加载 定义一个模型数组 用来保存数据 给控制器 或者外部使用
    lazy var gameModels:[JFGameModel] = [JFGameModel]()
}

extension JFGameViewModel{
     func requestGameData( finishCallBack:@escaping ()->()){
//        let parameters = ["shortName" : "game"]
        JFNetworkTool.requestData(type: .GET, urlString: "http://capi.douyucdn.cn/api/v1/getColumnDetail") { (response) in
            
            guard let response = response as? [String:Any] else { return }
                     
            // as? [String:NSObject] 转成数组 并且数组是字典类型
            guard let dataArray = response["data"] as? [[String:Any]] else { return}
            
            for dict in dataArray{
                self.gameModels.append(JFGameModel(dict: dict))
            }
            finishCallBack()
        }
    }
}

在这个viewmodel里面做网络请求,并懒加载一个模型数据暴露给外界(大部分情况是要给Controller持有的)

在控制器中懒加载一个ViewModel 并持有这个ViewModel

    fileprivate lazy var gameViewModel:JFGameViewModel =  JFGameViewModel()
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return gameViewModel.gameModels.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: KGameCellID, for: indexPath) as! JFCollectionGameCell
        let gameModel = gameViewModel.gameModels[indexPath.item]
        // cell.group = gameModel
        // Cannot assign value of type 'JFGameModel' to type 'AnchorGroup' 模型不匹配

        cell.baseGame = gameModel
        return cell
    }

使用viewModel中的数据 这样VC里面所有的数据都会由ViewModel去请求和加工 使VC更加清爽

image.png
image.png
 fileprivate lazy var topHeaderView:JFCollectionHeaderView = {
        let topView = JFCollectionHeaderView.collectionHeaderView()
        topView.frame = CGRect(x: 0, y: -(KHeaderViewH + KGameViewH), width: kScreenWidth, height: KHeaderViewH)
        topView.titleLabel.text = "常用"
        topView.iconImageView.image = UIImage(named: "Img_orange")
        topView.moreBtn.isHidden = true
        return topView
    }()

懒加载头部的视图

 override func setupUI(){
        
        contentView = collectionView
        
        super.setupUI()
        view.addSubview(collectionView)

        collectionView.addSubview(topHeaderView)

        collectionView.addSubview(gameView)

        collectionView.contentInset = UIEdgeInsets(top: KHeaderViewH + KGameViewH, left: 0, bottom: 0, right: 0)
        
    }

headerView添加在collectionView上
因为头部视图要随着collectionView的滚动而滚动

collectionView.contentInset = UIEdgeInsets(top: KHeaderViewH + KGameViewH, left: 0, bottom: 0, right: 0)

目的是计算好headerView的大小

在collectionView里面的代理方法和数据源方法进行 设置数据和UI

image.png
extension GameViewController:UICollectionViewDataSource{
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return gameViewModel.gameModels.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: KGameCellID, for: indexPath) as! JFCollectionGameCell
        let gameModel = gameViewModel.gameModels[indexPath.item]
        // cell.group = gameModel
        // Cannot assign value of type 'JFGameModel' to type 'AnchorGroup' 模型不匹配

        cell.baseGame = gameModel
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: KHeaderViewID, for: indexPath) as! JFCollectionHeaderView
//               let group = recommendVM.anchorGroups[indexPath.section]
//               headerView.anchorGroup = group
        headerView.titleLabel.text = "全部"
        headerView.iconImageView.image = UIImage(named: "Img_orange")
        headerView.moreBtn.isHidden = true
               
        return headerView
        
    }
}

这些基本上和OC的那套差不多

抽取基类


class BaseViewController: UIViewController {
    
    var contentView:UIView?
    
    
    fileprivate lazy var imageView:UIImageView = { [unowned self] in
        let imageView = UIImageView(image: UIImage(named: "img_loading_1"))
        imageView.center = self.view.center
        //数组中不能试可选类型
        imageView.animationImages = [UIImage(named: "img_loading_1")!,UIImage(named: "img_loading_2")!]
        imageView.animationDuration  = 0.5
        //LONG_MAX 非常大的整形
        imageView.animationRepeatCount = LONG_MAX
        
        //顶部和底部随父控件的 拉伸而拉伸
        imageView.autoresizingMask = [.flexibleTopMargin,.flexibleBottomMargin]
        
        return imageView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }
    
    func setupUI(){
        view.backgroundColor = UIColor.white
        contentView?.isHidden = true
        view.addSubview(imageView)
        imageView.startAnimating()
    }
    
    func loadDataFinished(){
        imageView.stopAnimating()
        imageView.isHidden = true
        contentView?.isHidden = false
        
    }
}

1、暴露一个contentView给外部 填充
2、loadDataFinished 暴露数据加载完成 刷新UI

好了 接下来

归纳下Swift一些常见且高频注意的点:

枚举类型

image.png

image.png
image.png

结构体

image.png
image.png

image.png

改变成员的属性,如果在函数红星改变成员的属性,那么该函数前必须加上mutating

加下滑"_" 代表参数可以 label 可以省略
image.png
image.png
image.png

类的基本使用

image.png

类里面定义属性 必须要对属性进行初始化

创建一个类用()创建 其实就是在调用构造函数

为什么 在类里面定义一个属性 必须要 对这个属性进行初始化

答案:应为类初始化的时候 会自动调用 初始化构建函数 而在这个是初话构建函数里面 会要求 里面的每一个属性进行初始化

image.png
image.png

好了今天就和大家分享到这
附上源码
源码
如果有啥问题希望大家一起纠正,非常感谢。
或者大家有想要的分享方式。我后续也会开始准备。
再见。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345