导言

在本篇文章之前的 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特点包装器声明的绑定特点。子视图能够运用这个绑定特点读取修正父视图中的特点值

拓展

  1. 在SwiftUI中,还有其他带有@符号的特点和特性,但它们却不是特点包装器。下面罗列我目前运用到的:

    • 视图构建:@ViewBuilder

      能够将多个视图作为闭包参数传递给函数,然后在函数中运用这些视图构建UI 层次

    • 函数特性:@escaping

      @escaping 主要用于函数参数的声明,用于函数类型参数的符号,用来指示该闭包参数逃逸闭包,会在函数执行完毕后继续存在并被调用

  2. 为什么要存在这么多不同层级的传递数据的特点包装器?

    这儿拿@ObservedObject@EnvironmentObject比照阐明,@EnvironmentObject已然能在大局同享数据,那为什么还需求@ObservedObject或许其他特点包装器

    尽管@EnvironmentObject在大局数据同享方面十分强壮,但并不是一切情况都适合运用它,而 @ObservedObject在某些场景下依然有其优势和用武之地:

    1. 部分性@ObservedObject更适用于视图的部分性数据同享。如果数据只在某个特定的视图层次结构内运用,将其作为@ObservedObject传递给子视图会更清晰和合适
    2. 粒度操控@ObservedObject答应您在不同层次的视图中运用不同的数据目标,每个视图能够有自己的数据源,而@EnvironmentObject会在整个应用程序中同享相同的数据目标
    3. 功能耗费:由于@EnvironmentObject是大局同享的,当应用程序中的多个视图都依赖于同一个@EnvironmentObject时,可能会导致功能问题。每次数据更改时,一切依赖于该目标的视图都会从头核算,这可能会导致不必要的功能耗费
    4. 测验宽和耦:运用@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()等特点包装器相同这些与数据状况、活动和传递相关,能完成在视图之间创立双向绑定