目录

1. @State  

2. @Binding 

3. @ObservedObject 和@Published 

4. @StateObject 

5. @EnvironmentObject和@Environment 

6. @AppStorage 


在 SwiftUI 中,属性包装用于增强和管理视图状态,以及处理视图与数据模型之间绑定交互。下面是一些常见的属性包装器:

1. @State  

使用@State属性包装器的变量私有的,并且仅在创建它们的视图中使用。当用户界面交互引起状态改变时,SwiftUI会重新绘制依赖这些状态的视图。这是响应编程思想在SwiftUI中的表现。

这里一个简单例子演示如何使用@State

import SwiftUI

struct ContentView: View {
    // 使用@State修饰计数器变量
    @State private var counter = 0

    var body: some View {
        VStack {
            Text("你点击了 (counter) 次")
            Button("点击我") {
                // 因为counter是@State变量,改变它的值将会重新绘制视图
                self.counter += 1
            }
        }
    }
}

这个例子中,每当counter变量的值改变时(例如用户每次点击按钮时),SwiftUI都会重新调用body属性,因此文本显示计数器值会更新

2. @Binding 

允许视图共享并能够双向绑定外部的状态。这常用于将父视图的状态传递给子视图。

@Binding 是一个属性包装器,它允许子视图共享父视图的状态。@Binding 为子视图提供对父视图的某个状态的引用,这样一来,子视图可以读取这个状态并能够在发生更改时更新它,而不是维护它自己的状态副本

当你使用 @Binding 时,它实际上是对一个 @State@ObservedObject@EnvironmentObject 或其他具有可观察状态的源的引用

以下是一个简单例子说明如何使用 @Binding

首先,假设你有一个父视图,使用 @State 管理一个布尔值 isOn

struct ParentView: View {
    @State private var isOn = false

    var body: some View {
        VStack {
            Toggle("Switch", isOn: $isOn)
            ChildView(isOn: $isOn) // 传递 @State 给子视图
        }
    }
}

接着,你有一个子视图 ChildView需要使用从父视图传递的 isOn 状态:

struct ChildView: View {
    @Binding var isOn: Bool // 使用 @Binding 接收父视图的状态

    var body: some View {
        Text(isOn ? "It's on" : "It's off")
    }
}

这个例子中,子视图 ChildView 可以直接显示 isOn 的状态,也能够在不同的视图层之间共享和修改这个状态,如果 isOn 在子视图中被修改,父视图中的 @State 也会相应更新。

3. @ObservedObject 和@Published 

@Published 通常用于 ObservableObject 里的属性。当给标记为 @Published 的属性赋值时,这个改动会发布出去,所有观察者可以接收这个改变。

@ObservedObject和 @Binding 类似,但是用于数据模型遵守 ObservableObject 协议时。它会使得视图自动更新以响应可观察对象中发生的变化。

 声明一个外部来源的可观察对象。当这个可观察对象发生变化时,使用 @ObservedObject 标记的视图会被重新绘制。这使得在SwiftUI中实现数据双向绑定和状态管理变得更加简单和直观。

这里有一些基础的概念和使用示例

可观察对象 (Observable Object)

可观察对象通常是遵循了 ObservableObject 协议的类,并且通过 @Published 属性包装器来声明那些当变化时需要通知视图重新渲染的属性。

import Combine
import SwiftUI

class ExampleModel: ObservableObject {
    @Published var score = 0
}

使用 @ObservedObject

在SwiftUI视图中使用 @ObservedObject 来观察这些对象的变化:

struct ExampleView: View {
    @ObservedObject var model: ExampleModel

    var body: some View {
        Text("Score: (model.score)")
            .onTapGesture {
                model.score += 10
            }
    }
}

这个例子中,每次点击文本时,模型的 score 属性会增加10。由于 score标记为 @Published,且 ExampleModel 遵循了 ObservableObject,所以每次 score 改变时,使用了 @ObservedObject 的 ExampleView 都将重新绘制,反映出新的分数

注意事项

@StateObject vs @ObservedObject

不要混淆 @ObservedObject 和 @StateObject

实践中,你需要根据实际的数据所有权和生命周期管理要求来选择使用 @StateObject 还是 @ObservedObject

4. @StateObject 

– 在 SwiftUI 2.0 中引入用来初始化可观察对象,并且拥有对该对象的所有权。也就是说它会构建并保持对象直到视图的整个生命周期结束

@StateObject 与 @ObservedObject 类似,都用于引用遵守 ObservableObject 协议的类实例。这种遵守 ObservableObject 协议的类会发布对其属性的更改,这样 SwiftUI 就可以在这些属性变化时更新 UI。

两者之间区别在于它们的用途和生命周期

在以下情形下使用 @StateObject

import SwiftUI

class ExampleModel: ObservableObject {
    @Published var count: Int = 0
    // Other properties and methods
}

struct ExampleView: View {
    @StateObject var model = ExampleModel()

    var body: some View {
        // UI elements that use 'model'
        Text("Count: (model.count)")
            .onTapGesture {
                model.count += 1
            }
    }
}

这个例子展示如何在视图中创建一个 @StateObject 以存储管理状态。在视图的生命周期中,ExampleModel 对象将保持活动并不会因为视图的重建而被销毁重置。使用这种方式,你可以确保状态的一致性并避免不必要的对象重建

5. @EnvironmentObject和@Environment 

@EnvironmentObject可以从环境获取共享的数据模型,这个属性包装器不负责创建对象,而是假定共享的对象已经被其它某部分代码添加环境中去了

@Environment 允许视图访问从 iOS 提供的环境值,例如 @Environment(.presentationMode) 可以访问视图的表现模式

@EnvironmentObject 和 @Environment 都是用于数据传递和状态共享的属性包装器,不过它们在使用中有一些区别

(1)@EnvironmentObject

@EnvironmentObject 用于向视图的层次结构中传递共享的数据对象。你可以在应用任意位置注入这个共享的数据对象,让其他需要这些数据的视图可以直接访问它,而不需要通过视图参数来逐层传递。这增加了数据共享的便捷性,尤其是在大型项目中。它通常用于类似于全局状态或者应用中的共享数据模型

使用@EnvironmentObject时,首先需要在某个视图之外的地方创建一个可观察对象。该对象需要遵守ObservableObject协议然后,在视图层次结构的上游 somewhere比如在顶级视图或者场景代理中) 你需要将这个对象作为环境对象注入。在需要访问这些数据的视图中,你使用@EnvironmentObject来声明这个依赖,然后 Swift UI会自动为你提供这个对象。

示例代码

class SharedData: ObservableObject {
    @Published var value: String = "Hello, World!"
}

struct ContentView: View {
    // 注入环境对象
    @EnvironmentObject var sharedData: SharedData

    var body: some View {
        Text(sharedData.value)
    }
}

let sharedData = SharedData()
let contentView = ContentView().environmentObject(sharedData)

如果尝试访问注入@EnvironmentObject应用崩溃

(2)@Environment

@Environment用于读取环境中传递下来的值,如系统设置接口样式布局方向等。相比@EnvironmentObject@Environment更多用于访问由 SwiftUI 框架维护的预设值,而不是自定义的可观测对象。一个常见的使用场景是,读取系统的颜色方案.colorScheme),或者是当前时间区域.timeZone)。

示例代码

struct ContentView: View {
    // 从环境中读取值
    @Environment(.colorScheme) var colorScheme

    var body: some View {
        Text("The current color scheme is (colorScheme == .dark ? "Dark" : "Light")")
    }
}

在这个例子中,我们没有注入任何自定义对象到环境中。相反,我们直接访问了 SwiftUI 环境中的预设值。

两者虽然看起来类似,但根据使用场景不同开发者可以选择最适合的一个。@EnvironmentObject 更适合那些全局共享状态的情景,而@Environment更适合需要访问由系统维护的环境值。

6. @AppStorage 

-在 SwiftUI 2.0 中引入,用于简单的数据持久化,当读写 UserDefaults 时自动同步视图。

@AppStorage 是一个 Swift 属性包装器(property wrapper),提供了一种将用户默认设置应用设置存储在 UserDefaults 中的便捷方式。使用 @AppStorage, 你可以创建一个绑定到 UserDefaults 中具体键的属性,当该属性的值发生变化时,UserDefaults 会自动更新,反之亦然。

在 SwiftUI 中,@AppStorage 的使用十分普遍,特别是用来响应某些设置或偏好的变化,并据此更新UI。这种数据持久化的方式适用于存储少量的用户配置信息例如标记应用是否为首次启动用户暗黑模式偏好、或者任何小型配置数据。

这里是一个基本的使用示例

import SwiftUI

struct ContentView: View {
    // 使用 @AppStorage 监视对应的 UserDefaults 键值对,当值变化时自动更新视图。
    @AppStorage("isDarkMode") private var isDarkMode = false

    var body: some View {
        VStack {
            Text(isDarkMode ? "Dark Mode is ON" : "Dark Mode is OFF")
            
            // 切换按钮可以更改 @AppStorage 绑定的值
            Button("Toggle Dark Mode") {
                isDarkMode.toggle()
            }
        }
    }
}

在上面的例子中,isDarkMode 属性绑定到了 UserDefaults 中的 "isDarkMode"键。当你点击按钮切换 isDarkMode 的值时,这个值会自动保存到 UserDefaults并在下次应用启动时保留。同时 UI 也会响应这个值的变化并立即更新。这种简单的数据绑定方法让你能够不必直接操作 UserDefaults API 而轻松保存和访问用户设置

官网SwiftUI | Apple Developer Documentation

原文地址:https://blog.csdn.net/SHUIYI_24/article/details/134684149

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_32948.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注