导言
在本篇文章之前的 iOS 入门系列(一)、iOS 入门系列(二)现已分别介绍了iOS 开发
的开发言语
、开发工具
以及开发结构
等内容。在本篇将会对SwiftUI 结构
中的数据状况和数据流
进行介绍
让数据状况和数据流
敞开我们入坑之旅的第二站吧~
State And Data Flow(数据状况和数据流)
在SwiftUI 结构
中是经过特点包装器
来办理数据的状况
、活动
和传递
的。数据状况和数据流
也是把握并进行iOS 开发
需求了解的要点常识~
下面便是SwiftUI
中的特点包装器,接下来会一一对其进行介绍:
- @State
- @Published
- @StateObject
- @ObservedObject
- @EnvironmentObject
- @Environment()
- @binding
@State
用于在视图内部
办理和维护时间短的、部分的状况
@State
特点包装器用于在视图内部办理和存储单一数据值
,它一般用于表明视图的内部状况
或用户界面的暂时状况
import SwiftUI
struct CounterView: View {
@State private var count: Int = 0
}
@State
直接在视图中声明变量后即可在视图内部办理和呼应数据的改变,然后完成视图的动态更新,运用较为频繁
@Published
用于在ObservableObject 类型
中符号特点,使其成为可被调查
的特点
@Published
特点包装器一般用于在ObservableObject
类中声明被发布的特点,以便在特点值发生改变时通知订阅者
import SwiftUI
class User: ObservableObject {
@Published var username: String = "Guest"
}
直接在ObservableObject 类型
的目标中声明被发布的特点,然后经过@StateObject
、@ObservedObject
、@EnvironmentObject
来完成订阅这些特点
@StateObject
用于在视图中创立
并维护一个持久化的、大局的ObservableObject 实例
@StateObject
适用于在视图内部创立和办理目标,它会主动在视图销毁时销毁目标。这一般用于ViewModel
,由于ViewModel 目标
的生命周期一般与视图相同
下面是运用@StateObject
的案例:
class ViewModel: ObservableObject {
@Published var data: String = "Initial Data"
}
struct ContentView: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
Text(viewModel.data)
.onTapGesture {
viewModel.data = "Updated Data"
}
}
}
能够看出,在view 视图
中经过@StateObject
声明的特点是在视图中自己创立的
@ObservedObject
用于在视图中引证
一个外部创立的ObservableObject 实例
@ObservedObject
适用于从外部传递目标给视图,而且希望视图能够调查该目标的改变。目标的生命周期不由视图办理,而是由传递者办理。适用于外部创立了一个目标并希望多个视图都能调查和运用它
class ViewModel: ObservableObject {
@Published var data: String = "Initial Data"
}
struct ContentView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
Text(viewModel.data)
.onTapGesture {
viewModel.data = "Updated Data"
}
}
}
struct ParentView: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
NavigationView {
NavigationLink(destination: ContentView(viewModel: viewModel)) {
Text("Go to ContentView")
}
}
}
}
能够看出,在view 视图
中经过@ObservedObject
声明的特点只是在视图中进行了声明,需求经过父视图
将目标传递给子视图
@EnvironmentObject
用于在整个应用程序
中同享一个ObservableObject 实例
@EnvironmentObject
适用于将目标在整个视图层次结构中主动传递给一切需求的视图。需求在应用程序的根视图
中将一个自定义的数据目标设置为环境目标
。然后多个视图
就能够同享
相同的数据,并在数据改变时进行主动更新
根视图设置环境目标
class UserModel: ObservableObject {
@Published var username: String = ""
@Published var age: Int = 0
}
@main
struct YourApp: App {
@StateObject private var userModel = UserModel()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(userModel)
}
}
}
@EnvironmentObject 声明目标
struct ContentView: View {
@EnvironmentObject var userModel: UserModel
var body: some View {
VStack {
Text("Username: \(userModel.username)")
Text("Age: \(userModel.age)")
}
}
}
@Environment()
用于在视图
中拜访体系提供的环境变量
@Environment
特点包装器用于拜访环境变量,这些变量由体系提供或在应用程序规模内设置
struct ContentView: View {
@Environment(\.colorScheme) var colorScheme
var body: some View {
if colorScheme == .dark {
Text("Dark Mode")
.foregroundColor(.white)
.background(Color.black)
} else {
Text("Light Mode")
.foregroundColor(.black)
.background(Color.white)
}
}
}
经过体系提供的.colorScheme
变量来拜访当时的颜色方案,@Environment()
在拜访体系变量
时需求带上\
@binding
用于在视图之间
双向绑定特点,完成数据传递和同步
@Binding
特点包装器用于在父视图中创立一个绑定,然后将其传递给子视图,以便子视图能够修正父视图中的数据。这关于在视图层次结构中同享数据十分有用
import SwiftUI
struct ContentView: View {
@State private var isToggleOn = false
var body: some View {
ToggleView(isOn: $isToggleOn)
.padding()
}
}
struct ToggleView: View {
@Binding var isOn: Bool
var body: some View {
Toggle("Toggle", isOn: $isOn)
}
}
在父视图
中创立一个特点并将其符号为@State
或其他可修正的特点包装器
,然后将这个特点传递给子视图
中用@Binding
特点包装器声明的绑定特点
。子视图能够运用这个绑定特点
来读取
和修正
父视图中的特点值
拓展
-
在SwiftUI中,还有其他带有@符号的特点和特性,但它们却不是特点包装器。下面罗列我目前运用到的:
-
视图构建:
@ViewBuilder
能够将
多个视图
作为闭包参数
传递给函数,然后在函数中运用这些视图构建UI 层次
-
函数特性:
@escaping
@escaping
主要用于函数参数的声明
,用于函数类型参数的符号,用来指示该闭包参数
是逃逸闭包
,会在函数执行完毕后继续存在并被调用
-
-
为什么要存在这么多不同层级的传递数据的特点包装器?
这儿拿
@ObservedObject
和@EnvironmentObject
比照阐明,@EnvironmentObject
已然能在大局同享数据,那为什么还需求@ObservedObject
或许其他特点包装器
?尽管
@EnvironmentObject
在大局数据同享方面十分强壮,但并不是一切情况都适合运用它,而@ObservedObject
在某些场景下依然有其优势和用武之地:-
部分性:
@ObservedObject
更适用于视图的部分性数据同享
。如果数据只在某个特定的视图层次结构内运用,将其作为@ObservedObject
传递给子视图会更清晰和合适 -
粒度操控:
@ObservedObject
答应您在不同层次的视图中运用不同的数据目标,每个视图能够有自己的数据源,而@EnvironmentObject
会在整个应用程序中同享相同的数据目标 -
功能耗费:由于
@EnvironmentObject
是大局同享的,当应用程序中的多个视图都依赖于同一个@EnvironmentObject
时,可能会导致功能问题。每次数据更改时,一切依赖于该目标的视图都会从头核算,这可能会导致不必要的功能耗费 -
测验宽和耦:运用
@ObservedObject
能够更简单进行单元测验,由于您能够更精确地操控要传递的数据目标。此外,运用@ObservedObject
能够更好地解耦视图,使其愈加独立和可复用
综上所述,
@EnvironmentObject
在大局数据同享方面是十分强壮的,但在一些特定场景下,运用@ObservedObject
可能愈加合适,以达到更好的功能、测验宽和耦作用 -
部分性:
小结
本文主要是针对SwiftUI
中特点包装器
关于视图及视图间
的数据状况和数据流
的办理,下面就对全文做一个简要总结
@State
和@Published
运用及了解起来相对简单,一个是在视图内
声明单一数据值
,一个是在ObservableObject 类型目标
中声明被发布的特点值
@StateObject
、@ObservedObject
在运用时可能会存在一些困惑,但只要牢记@StateObject
是在视图内创立ObservableObject 实例
,而@ObservedObject
则是在视图内引证ObservableObject 实例
即可
@ObservedObject
和@EnvironmentObject
在了解上也会存在一些疑惑,但只要明白:@ObservedObject
需求经过父视图将目标传递给子视图,而@EnvironmentObject
只需求在根视图中传递一次,之后一切视图都能同享这个目标;@ObservedObject
更适用于部分规模的数据同享,而@EnvironmentObject
更适用于大局规模的数据同享的概念后也能正确运用它们了
@EnvironmentObject
和@Environment()
尽管长得相似,但是也是不同的,@EnvironmentObject
用于在视图之间同享自定义数据目标,而@Environment
用于拜访体系提供的环境变量
@binding
也同@State
、@Published
、@StateObject
、@ObservedObject
、@EnvironmentObject
、@Environment()
等特点包装器相同这些与数据状况、活动和传递相关,能完成在视图之间
创立双向绑定