SwiftUI实战-仿写微信App(六)
一、跨层级数据共享
前面的章节提到过,父级使用@State
修饰变量,子级使用@Binding
修饰变量,并通过参数的传递,可以实现变量的共享即不管是父级还是子级改变该变量的值,对方都会感知到。
共享共享父级变量子级
但是还有一种情况,就是数据在多个View
中都有引用,它们并不是父子级的关系,也希望共享该变量。
共享共享View1变量View3View2.1View2.2
View1和View3都持有该变量,但是并非父子级关系。
二、Combine框架
SwiftUI
提供了一个框架Combine
,使用MVVM
设计模式。
MVVM
是Model-View-ViewModel
的简写。
Model
指代共享变量。View
就是视图层,同上文的View1,View2,View3
。ViewModel
类似一个枢纽,把Model
和View
联结起来。
ViewViewModelModel
ViewModel
持有变量Model
,通过某些手段(后面会讲)将Model
变成共享变量。View
中引入ViewModel
类,通过ViewModel
操作Model
,比如增删改等操作,其它引用View
都会得到通知。
三、ModelView
先创建一个ModelView
类。Xcode
创建Swift File
而非SwiftUI View
import Foundation class AnimalViewModel{ } 复制代码
注意:这里
ViewModel
必须是class
,而不是struct
。
然后实现ObservableObject
协议,通知SwiftUI
这是一个ViewModel
类。
四、Model
接下来在ViewModel
中创建Model
。
class AnimalViewModel: ObservableObject{ var animals: [String] = [] } 复制代码
Model
不拘泥数据类型,不管是数组,还是其它类型均可,即使是一个Bool
变量都可以。
同理Model
也需要证明自己,所以使用@Publish
注解修饰。
@Published var animals: [String] = [] 复制代码
五、View
在View
中引用ViewModel
。
创建两个View
:TVView
和PCView
,分别引入ViewModel
,并显示同样的List
列表。
比如TVView
,PCView
同TVView
。
struct TVView: View { var model: AnimalViewModel var body: some View { List{ Text("TVView") Button(action: { model.animals.append("cat") }, label: { Text("addAnimal") }) ForEach(0..<model.animals.count, id: \.self){index in Text(model.animals[index]) } } } } 复制代码
同前面两步,View
同样需要通知SwiftUI
它对ViewModel
的引用。使用@EnvironmentObject
修饰ViewModel
。
@EnvironmentObject var model: AnimalViewModel 复制代码
六、ViewModel
层级
最后,虽然使用@EnvironmentObject
注解标记了ViewModel
,但是没有通知SwiftUI
在哪创建ViewModel
,也即在哪个View
层级上创建ViewModel
。
View1上创建ViewModelView2.1上创建ViewModelView1View2.2View3.3View3.4View3.1View2.1View3.2
如上图,
如果在View1
层级创建ViewModel
,Model
能够在View1
、View2
和View3
所有层级中共享。
如果在View2.1
层级创建,Model
只能在View2.1
、View3.1
和View3.2
中共享。
那么具体怎么创建呢?
在WeChatModel
项目中,ContentView
作为最上级的View
,只需要找到创建ContentView
的位置。
如下图
看清楚,虽然都是EnvironmentObject
,一个是使用@EnvironmentObject
注解标记View
中的ViewModel
,另一个是指定ViewModel
的影响范围。
我们只需要指定影响范围即可,具体什么时间创建,是由
SwiftUI
自己决定的。
最终效果如下:
附:代码地址
作者:徒手完结
链接:https://juejin.cn/post/6993312402913624094