2021-05-26

SwiftUI 简明教程之属性包装器

本文为 Eul 样章,如果您喜欢,请移步 AppStore/Eul 查看更多内容。

Eul 是一款 SwiftUI & Combine 教程 App(iOS、macOS),以文章(文字、图片、代码)配合真机示例(Xcode 12+、iOS 14+,macOS 11+)的形式呈现给读者。笔者意在尽可能使用简洁明了的语言阐述 SwiftUI & Combine 相关的知识,使读者能快速掌握并在 iOS 开发中实践。

常用属性包装器

SwiftUI 提供了许多的属性包装器(Property Wrapper),极大简化了我们的工作。属性包装器,实际上是对声明的属性做了一层封装,在内部实现了一些我们看不见的操作。

下面会在概念和使用上简介 SwiftUI 中常用的属性包装器,不在代码层面做具体演示。更详细的内容可以参见我的两篇文章:

  • SwiftUI-中常见的属性包装器(Property-Wrapper)概览
  • SwiftUI(iOS-14)新增属性包装器(Property-Wrapper)

@State

在当前 View 中声明,通常使用 private 修饰,当修饰的属性值改变时,界面会随之更新。

@Binding

接收从外部对象传入的绑定值,同时可以将属性的变化回传给外部对象,即数据是双向绑定的。如 A 的属性 @State private var value: String 传入 B 的属性 @Binding var value: String ,当 B 中的 value 值改变时, A 的 value 也会更新。

@Environment

访问预设的环境变量,如系统的暗黑模式、时区等。

@ObservedObject、@Published

@ObservedObject 可以修饰遵循 ObservableObject 协议的 class 对象,该对象实例中的属性可以使用 @Published 修饰。当使用 @Published 修饰的属性值发生改变时,所有使用 @ObservedObject 修饰的对象实例,都会更新相应的值,通常用于在多个界面之间同步数据和状态。

@StateObject

与 @ObservedObject 一样,@StateObject 修饰的对象同样是遵循 ObservableObject 协议的 class 对象。但是区别在于,@StateObject 修饰的对象只会在所属的 View 中创建一次并在 View 的生命周期内存储相应的状态,而 @ObservedObject 修饰的对象会随着 View 的重绘生成新的对象,不会在 View 的生命周期内存储该对象的状态。

@EnvironmentObject

@EnvironmentObject 修饰的对象同样需要遵循 ObservableObject 协议,与 @ObservedObject 功能类似,但是它有着更强大的功能,子视图可以直接获取父视图注入的环境变量。比如,我们有视图 A、B、C,A 包含 B,B 包含 C,如果我们使用 @ObservedObject 来传递变量,需要从 A 传入 B,再从 B 传入 C,C 才能获取到对应的变量。而 @EnvironmentObject 无需如此繁琐,我们直接通过父视图 A 注入环境变量,视图 C 就可以获取注入的变量,省去中间的传递过程。

@AppStorage

等同于 Userdefaults。

@SceneStorage

用于多窗口模式,相当于为每个场景持久化了一个场景值,每个场景只能读取该场景持久化的值。当场景销毁时,该值也会销毁。建议存储轻量的、不敏感的数据

@UIApplicationDelegateAdaptor

用来调用 AppDelegate 中的生命周期方法。

自定义属性包装器

使用属性包装器可以使我们的代码精简,那么如何根据需求自定义呢?

自定义的属性包装器需要使用 @propertyWrapper 声明,并且必须有一个名为 wrappedValue 的属性。例如下面的代码,通过 CNNumber 这样一个属性包装器,可以将字符串中的阿拉伯数字转化成中文数字:

@propertyWrapperstruct CNNumber { private let table = [ "0" : "〇", "1" : "一", "2" : "二", "3" : "三", "4" : "四", "5" : "五", "6" : "六", "7" : "七", "8" : "八", "9" : "九", ] private var value = "" var wrappedValue: String { get { value } set { value = convertToCNNumbers(newValue) } } init(wrappedValue: String) { self.wrappedValue = wrappedValue } func convertToCNNumbers(_ string: String) -> String { var res = "" for v in string {  res += table[String(v)] ?? "" } return res }}

然后我们定义一个 Person 结构体,使用 CNNumber 去修饰 birth 属性,调用时正如示例所示,它被转换成了中文数字。

struct Person { var name: String @CNNumber var birth: String}struct ContentView: View { private let p = Person(name: "Steve Jobs", birth: "1955年2月24日") var body: some View { Text(p.birth) }}

本文为 Eul 样章,如果您喜欢,请移步 AppStore/Eul 查看更多内容。









原文转载:http://www.shaoqun.com/a/761806.html

跨境电商:https://www.ikjzd.com/

tenso:https://www.ikjzd.com/w/1552.html

浩方:https://www.ikjzd.com/w/1046


本文为Eul样章,如果您喜欢,请移步AppStore/Eul查看更多内容。Eul是一款SwiftUI&Combine教程App(iOS、macOS),以文章(文字、图片、代码)配合真机示例(Xcode12+、iOS14+,macOS11+)的形式呈现给读者。笔者意在尽可能使用简洁明了的语言阐述SwiftUI&Combine相关的知识,使读者能快速掌握并在iOS开发中实践。常用属性包
铭宣海淘:https://www.ikjzd.com/w/1551
刘军:https://www.ikjzd.com/w/1835
声网:https://www.ikjzd.com/w/2176
口述:我和单位小男生赤裸相对:http://lady.shaoqun.com/m/a/272664.html
黑客已窃取约100个亚马逊账户的资金:https://www.ikjzd.com/articles/91318
校花练车时给教练插了 儿媳在公交车让公爹插 女孩张开裙子给男生捅:http://www.30bags.com/m/a/249676.html

No comments:

Post a Comment