75142913在线留言
CS193P2021学习笔记第三课:MVVM开发模式与Swift类型系统_IOS开发_网络人

CS193P2021学习笔记第三课:MVVM开发模式与Swift类型系统

Kwok 发表于:2021-08-09 16:09:20 点击:5 评论: 0

上一节课里我们学习了很多swiftUI的创建知识,本节课的重点是将数据与UI连接起来。也就是”记忆游戏“的逻辑处理部分。

一、MVVM 数据流向

MVVM = Model - View - ViewModel的缩写,用户明确代码所不同的组件的位置以及它们如果相互交互。SwiftUI必须使用MVVM开发模式。这是与MVC完全不同的开发模式,所以我们应该完全理解这种开发的方式。

1、Model 模型完全独立于UI,主要存放的是逻辑代码与数据(类似SQL数据库、或者来源于服务器的远程数据),使用sruct定义,描述应用程序”做什么“的所有数据和逻辑操作。数据的唯一真实来源(The Truth)我们永远不会复制的数据。

2、View 视图是程序”如何“呈现给用户(上节课学的VStack、Text等)反应模型的当前状态。这反应出View是无状态的,所有的数据都存在于Model里。视图是不可变的,只能被重建。视图的代码本质上是一种解释性语言,通过Model的变化解释UI。视图是立即全部生成的,并不是随着时间轴逐步生成,所以显示的是已画好的原始的动画图片一样。视图总是随着数据的变化而自动变化(响应势的)

3、ViewModel 视图模型主要的工作是将视图与模型绑定在一起,以便模型中的更改导致视图做出反应并重建变化。是模型和视图之间的一种解释器。在具体的工作中,VM可以将来源于M的整数转换成浮点数交给V使用。VM是一个非常好的助手。View允许调用VM中的函数与变量。而VM可以使用M里的数据与功能函数,VM永远不会存储数据。

总结一下。M = Model 用啥数据做点啥、V = View 根据VM的指示来显示啥给用户看、VM = ViewModel 属于Model与View之间的连接桥梁或者胶水。本质上来讲,MVVM的工作实际上只是将模型M(Model)通过VM(ViewModel)连接到视图V(View)。也可以理解为视图(View)通过从视图模型(ViewModel)请求来自于模型(Model)的数据。

CS193P2021学习笔记第三课MVVM开发模式与Swift类型系统

(以上图片来自CS193P 2021课程视图截图)

通过理解MVVM我们要知道学习一个完整的APP开发需要掌握3个结构性的代码,即:数据模型、视图代码、视图模型代码。目前来说视图代码(解释性语言)应该是最好学的,只需要死记即可,要深入学习必须掌握好Model与ViewModel的代码。之所以要分成这3部分来写,是为了让我们的代码更好的分工处理业务逻辑。让代码做自己擅长的事情。MVVM数据流向专门说明:http://www.neter8.com/ios/114.html

二、Swift Type System 类型系统

1、struct 结构体

 与class类似,但他们有本质上的区别,一个是值类型struct,一个是引用类型class。

2、class 类

关于使用介绍与区别,老师讲的和我以前写的差不多:http://www.neter8.com/ios/104.html 

CS193P2021学习笔记第三课MVVM开发模式与Swift类型系统

最后总结一下它们的初始化区别,Class与Struct都获得了自动初始化init(),但不同的是结构体的每一个公开变量都会被init初始化,但class是一个没有参数的init初始化,也就是说class是不能通过免费的init对成员变量进行初始化操作的。

3、protocol协议

 协议是非常强大与重要的类型,光是系统自带的协议搞明白了就很厉害了。关于协议的介绍:http://www.neter8.com/ios/105.html

4、”Dont' Care“ type (aka generics) 泛型

 把泛型直译一下叫着通用类型更能直接明了的理解,因为swift是强类型的语言,调用或者声明结构体、类、函数的时候必须指定数据类型,当我们使用自己定义的类型时候,不确定叫什么名称,或者要让我们写的代码可以处理多种满足条件的数据类型时,我们就需要声明一个泛型来处理。

泛型主要是为了向后兼容而应运而生的数据类型。泛型是编译器在编码时检查该数据类型是否可用,由编译器自动转换数据类型。

Array 是swift里最能让人容易理解的泛型,当在实例化Array时,指定数据类型为Int,哪么里面就存的是整数,指定为String,那么里面存的就是字符串,所以定义Array的时候,就需要把类型定义为泛型即可。

//初始化时编译器将使用实际的数据类型替换
struct Array<Element>{
    ...
    func append(_ element:Element){...}
}

泛型很好理解,我们只需要把<Element>做为一个替代类型的占位符来使用,这里的Array接受任何的数据类型,调用append的时候,我们接受一个element的参数,而大写的Element则是数据的类型。

var a = Array<Int>()//现在Element就是Int
a.append(5)//调用append方法
a.append(2)//

当然有时候 我们需要对数据类型有一点条件限制的时候,在struct的<Element>后面加上"where"即可。

5、enum 枚举

 详细介绍:http://www.neter8.com/ios/103.html

6、functions 函数

详细介绍函数与闭包的使用:http://www.neter8.com/ios/101.html

三、代码编写

课程理论部分的讲解完成后,需要通过代码实际编写深入理解MVVM开发模式,上一节课里我们已写好了View,下面就需要写一下Model与ViewModel。

1、Model 模型

新建一个Swift file 保存为MemoryGame.swift 内容为:

import Foundation //此包导入了Array、String、Int等基本的数据类型
//CardContent 就是课程前面介绍的泛型定义
struct MemoryGame<CardContent> {
    private(set) var cards:Array<Card>//卡片只读,在任何情况下只能使用内部函数对数据进行CRUD
    func choose(card:Card) {
        
    }
    //初始化卡片个数及使用闭包确定卡片的内容是什么
    init(numberOfPairsOfCards: Int, createCardContent:(Int) -> CardContent) {
        cards = Array<Card>()//初始化卡片容器
        //让卡片在容器里成对出现,通过numberOfPairsOfCards指定个数
        for pairIndex in 0..<numberOfPairsOfCards{
            let content = createCardContent(pairIndex)//使用闭包来获取到卡片的内容(传入的是当前索引Int实参)
            cards.append(Card(content: content))//容器增加一个卡片内容
            cards.append(Card(content: content))//容易再增加一个内容相同的卡片
        }
    }
    
    
    //将Card嵌套在MemoryGame结构体里主要目的是外部如果想要调用时需要输入MemoryGame.Card(识别命名)
    struct Card {
        var isFaceUp:Bool = false //初始不朝上
        var isMatched:Bool = false //初始不匹配
        var content:CardContent //卡片内容也许会是图片、字符、数字等,这里使用了泛型
    }
}

上面的Model里定义了2个结构体(struct),一个是记忆游戏(MemoryGame)本身和一个卡片(Card)的数据结构,而卡片(Card)被嵌套在了记忆游戏(MemoryGame)里,因为他们有一定的依赖关系,所以放到一起不会在大型开发中污染到其它的数据命名。

2、ViewModel 视图模型

新建一个Swift file文件命名为EmojiMemoryGame.swift,内容如下:

import SwiftUI//VM必须导入swiftUI包,使用的代码和数据类型,以CG开头的如CGFloat、CGSize等
//ViewModel 主要充当View与Model的连接作用
class EmojiMemoryGame {
    //使用静态化成员本质上在此类里是全局性的,使用“类名.成员名”的方式直接访问,像结构体里嵌套了Card结构原理一样。
    static let emojis = ["🪰","🦘","🐌","🐤","🦎","🐶","🐱","🐭","🐝","🏓","🥎","🏏","⛹🏼‍♀️","🚗","🦯","✈️","🚅","🚆","🚊","🚜","🛳","🚈","📀","🧭","🖨","⌚️","📡"]

    //使用函数创建并初始化游戏
    static func createMemoryGame() -> MemoryGame<String>{
        //通过MemoryGame的初始化生成卡片的个数,然后通过闭包函数获取到内容表情(这里的pairIndex是函数形参)
        MemoryGame<String>(numberOfPairsOfCards: 4){ pairIndex in
            EmojiMemoryGame.emojis[pairIndex] //通过传入的实参值返回表情[序列]内容
        }
    }
    //创建MemoryGame的时候我们必须要像数组一样指定泛型的类型
    private var model:MemoryGame<String> = createMemoryGame()//创建与Model的数据链接,并保护起来免受View对数据的破坏
    //通过model保护数据,并通过cards让数据只读
    var cards:Array<MemoryGame<String>.Card>{
        model.cards
    }
}

可以看到他们的虽然导入的包不一样,但是命名却比较接近,Mode的名字叫:MemoryGame.swift而ViewMode的名字叫:EmojiMemoryGame.swift区别于VM多了一个Emoji,这里的VM表示为我们的游戏内容为Emoji,如果我们建一个NumberMemoryGame.swift的VM就可以理解为游戏的内容是数字,imageMemoryGame表示为图片记忆游戏,以此类推对游戏进行一个扩展操作。做为新手区别和理解Model和ViewModel是很重要的。一个是结构体(struct)一个是类(class)。

除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:http://www.neter8.com/ios/147.html
标签:MVVM笔记cs193pKwok最后编辑于:2021-08-16 14:16:42
1
感谢打赏!

《CS193P2021学习笔记第三课:MVVM开发模式与Swift类型系统》的网友评论(0)

本站推荐阅读

热门点击文章