https://www.bilibili.com/video/BV1q64y1d7x5?p=3
MVVM
全称Model-View-ViewModel
是一种设计范式(design paradigm),清楚的说明了组件的组织形式以及交互形式。
MVVM
包含用户界面代码(View)
、应用程序逻辑(Model)
与ViewModel
。
Model完全独立于UI,由数据(Data)
和逻辑(Logic)
构成。
View是Model状态的一种反射(reflection)
,用以显示当前Model的状态。这意味着View几乎是无状态(stateless)
的,View中的@State
仅仅用来重绘界面,其本质依然是stateless
。
View的代码是声明性(Declared)
的,其UI直接由body var
所定义,类似于Futter、RN等UI框架。
View是响应式 (Reactive)
的,View的body var
会随着Model的变化而变化,使界面不断的重绘。
View的响应式是由ViewModel促成的
ViewModel用于Model与View的绑定,是一种Model与View之间的解释器(Interpreter)
。
ViewModel还充当Model的守门人(Gatekeeper)
,使Model能够正确的被修改。(说白了就是类变量私有化,以保护该变量)
Model的数据通过ViewModel向View传递。其中,ViewModel会不断跟踪Model的变化(notices changes)。当Model变化时,ViewModel会发送公告,让所有View都知道Model的变化,因此,ViewModel不与任何View绑定。View可以订阅ViewModel的公告,以获取公告的内容并请求body var要求重绘UI。
Model -> ViewModel -> View有关的关键词:
Model -> ViewModel : ObservableObject、@Published、objectWillChange.send()
ViewModel -> View : @ObservedObject、@Binding、.onReceive、@Environment Object、.environmentObject()
用户的意图(intent)
也可以通过View -> ViewModel -> Model
传递。其中,View将用户的意图发送给ViewModel(call intent function),然后ViewModel转换这些意图发送给Model并对Model进行修改。
这里的意图Intent,就是用户在屏幕上的操作。如点击、滑动等。
Swift有struct、class、protocel、generic、enum与function。
本节视频课程没有讲protocel与enum,因此只总结另外四种。
相同点:
都可以存储常量(let)与变量(var)
都可以定义函数(function)
// 第一种函数定义
func multiply(operand: Int, by: Int) -> Int {
return operand * by
}
multiply(operand: 5, by: 6)
// 第二种函数定义
func multiply(_ operand: Int, by otherOperand: Int) -> Int {
return operand * otherOperand
}
multiply(5, by: 6)
都有初始化器(initializer)
struct/class ClassOrStructName{
init(number: Int){
// 第一个init
}
init(anotherNumber: Int){
// 可以有多个init
}
}
不同点:
struct | class | ||
---|---|---|---|
值类型 | Value type | 引用类型 | Reference type |
写时复制 | Copy on write。复制后并没有得到真正的副本,当对数据进行修改时才会得到副本。 | 自动引用计数 | Automatically reference counted。swift会记录指向该class的指针数目,当没有指针指向该class时,会将其从堆中清除以释放内存 |
函数式编程 | Functional programming | 面向对象编程 | Object-oriented programming |
无继承 | No inheritance | 单一继承 | Inheritance(single) |
可以init | “Free” init initializes ALL vars | 必须init | “Free” init initializes NO vars |
Mutability must be explicitly stated | Always mutable |
尽量使用struct
struct Array<Element> {
···
func append(_ element: Element) { ··· }
}
var a = Array<Int>()
a.append(5)
func square(operand: Double) -> Double {
return operand * operand
}
operantion = square
let result = operation(4)
内联函数,又称“
闭包(Closures)
”
代码来自视频课程中Memory游戏项目的实例。老师着重讲了Model与ViewModel部分,View部分等到下一节再补充。
import Foundation
//Model
struct MemoryGame<CardContend>{
//private(set) 代表只读
private(set) var cards: Array<Card>
func choose(_ card: Card){
}
init(numberOfPairsOfCards: Int,createCardContent: (Int) -> CardContend){
cards = Array<Card>()
for pairIndex in 0..<numberOfPairsOfCards{
let content = createCardContent(pairIndex)
cards.append(Card(content: content))
cards.append(Card(content: content))
}
}
//MemoryGame.Card
struct Card{
var isFaceUp: Bool = false
var isMatched: Bool = false
var content : CardContend
}
}
//ViewModel
class EmojiMemoryGame{
//static类型的初始化顺序在普通var之前
//因此static类型的类成员可以作为其他类成员的默认值使用
//如 var a = EmojiMemoryGame.emojis[1]
static var emojis = ["","","","","","","","","","",
"","","","","","","","","","",""]
static func createMemoryGame() -> MemoryGame<String> {
return MemoryGame<String>(numberOfPairsOfCards: 2, createCardContent: {
// 定义中:createCardContent: (Int) -> CardContend //CardContend是一个泛型
// 因此,此处会自动识别类型,将
// index in 识别为 (index: Int) -> String in
index in
return EmojiMemoryGame.emojis[index]
} )
}
private var model: MemoryGame<String> = EmojiMemoryGame.createMemoryGame()
var cards: Array<MemoryGame<String>.Card>{
//只读
return model.cards
}
}