@Lazy:参见惰性属性
自定义属性包装器,用于延迟初始化属性,只有在首次访问时才进行初始化。这对于代价昂贵的初始化操作非常有用。
@NSCopying
自定义属性包装器,用于确保属性始终是一个副本,而不是引用。这对于处理可变对象时非常有用。
@AutoClosure
自定义属性包装器,用于自动封装表达式为闭包,使其在需要时被延迟执行。
@available
用于标记属性的可用性,以指定在不同版本的 Swift 或操作系统中是否可用。
@escaping
在Swift中,将 @escaping
关键词添加到函数参数中,表示该闭包可以超出函数调用范围而继续存在。
这意味着闭包可能会在函数执行完毕后继续存在,并且可能被存储在其他地方以供稍后调用。这种情况通常发生在需要异步操作的函数中,例如回调函数。通过使用@escaping关键词,告诉函数调用者闭包的生命周期可能会超出函数范围,因此调用者需要注意避免保留循环和内存泄漏。这也告诉Swift编译器这是有意为之的。在闭包可能会超出函数作用域的情况下,必须使用 @escaping
关键词。
onSave
闭包在函数返回后执行,那么使用 @escaping
是正确的做法。这样的闭包可以在函数执行完毕后继续执行,以完成异步操作或其他需要延迟执行的任务。@escaping
关键词用于 onSave 参数,这意味着 onSave 闭包可能会在 init 函数返回后执行。@escaping
闭包参数 onSave 用于保存位置信息。这样的闭包通常用于异步操作的回调,因为它们可以在函数返回后执行,例如保存位置信息后更新用户界面。init(location: Location, onSave: @escaping (Location) -> Void) {
self.location = location
self.onSave = onSave
_name = State(initialValue: location.name)
_description = State(initialValue: location.description)
}
<aside>
💡 在使用 @escaping
闭包时,需要注意避免循环引用和内存泄漏问题。
</aside>
@State :参见 @State
@State
关键词:是一个特殊的属性或特殊的数据,在宣告属性为 @State 時,SwiftUI 会管理 该参数的儲存方式,无论在哪里改变它,都会刷新body,这样一来,body和状态将始终同步。SwiftUI就是通过这样的方式,让用户界面和状态总是一致。
@Binding :参见 @Binding 和 @Bindable
@Binding
关键词:用于组件视图和主视图之间的数据沟通。有时候,当抽出子视图后,有些变量会放到子视图,而不是主视图 ContentView 。那子视图 和 主界面之间的数据如何绑定呢?这时就要用到 @Binding
来和主界面的参数绑定在一起了。
@Environment :参见 @
Environment
用于 SwiftUI 中,用于获取环境变量的值,例如主题、字体设置等。通过 @Environment
属性包装器,你可以轻松访问这些环境值。
以下几个已逐渐被弃用,参见:@EnvironmentObject
**@Published:**将属性标记为 @Published
以便在数据发生更改时发布通知,通常与 ObservableObject
一起使用,用于视图中的数据绑定
**@ObservedObject:**在视图中引入遵循 ObservableObject
协议的数据模型。它创建一个与数据模型的绑定,以便在数据变化时触发视图的更新
**@EnvironmentObject:**将 ObservableObject
对象注入环境
属性包装器实际上只是一些技巧:它们将一个简单的值包装在另一个值中,以便可以添加一些额外的功能。不管是通过 @State
在其他地方存储值,还是使用 @Environment
从共享数据源读取值,其原理是相同的。
我们甚至可以自定义自己的属性包装器。例如从包装某种 BinaryInteger
值的简单结构开始,在设置其包装值时,我们将给这个包装器一些自定义代码(如果新值低于 0,就会将其设置为 0,这样该结构就永远不会为负数),代码如下所示:
struct NonNegative <Value: BinaryInteger> {
var value: Value
init(wrappedValue: Value) {
if wrappedValue < 0 {
value = 0
} else {
value = wrappedValue
}
}
var wrappedValue: Value {
get { value }
set {
if newValue < 0 {
value = 0
} else {
value = newValue
}
}
}
}
//现在可以用一个整数来创建它,但如果该整数低于 0,那么它将被限制为 0
var example = NonNegative(wrappedValue: 5)
example.wrappedValue -= 10
print(example.wrappedValue) //打印 0
属性包装器可以将其用于结构或类中的任何类型的属性。要实现这个只需要一步:
//1. 在 NonNegative 结构体之前写入 @propertyWrapper ,即可拥有自己的属性包装器!
@propertyWrapper
struct NonNegative <Value: BinaryInteger> {
...
}
//2. 具体使用
//属性包装器只能用于属性,而不能用于普通变量或常量,因此为了尝试包装器,必须将它放在像这样的 User 结构中
struct User {
@NonNegative var score = 0
}
var user = User()
user.score += 10
print(user.score)
user.score -= 20 //打印 0
print(user.score)
这里没有什么神奇之处:属性包装器只是将一条数据包裹在另一条数据周围的语法糖。如果需要我们也可以自己制作它们。
SwiftUI 中常用的环境值有以下这些,我们可以从环境中获取它们的值,赋予变量:@Environment(\\.colorScheme) var colorScheme
名称 | 用途说明 | 枚举值或示范用例 |
---|---|---|
colorScheme | 当前系统的颜色模式(浅色或深色) | .dark , .light |
colorSchemeContrast | 当前颜色模式的对比度设置 | .standard , .increased |
accessibilityEnabled | 当前是否启用了辅助功能 | true , false |
locale | 当前应用的语言环境设置 | Locale.current |
calendar | 当前系统使用的日历 | Calendar.current |
timeZone | 当前系统使用的时区 | TimeZone.current |
displayScale | 获取当前显示屏的缩放比例 | 2.0, 3.0 |
sizeCategory | 当前的内容大小类别(字体大小) | .extraSmall , .small , .medium , .large , .extraLarge , .extraExtraLarge , .extraExtraExtraLarge , .accessibilityMedium , .accessibilityLarge , .accessibilityExtraLarge , .accessibilityExtraExtraLarge , .accessibilityExtraExtraExtraLarge |
horizontalSizeClass | 当前界面的水平尺寸类别(紧凑或常规) | .compact , .regular |
verticalSizeClass | 当前界面的垂直尺寸类别(紧凑或常规) | .compact , .regular |
layoutDirection | 当前界面的布局方向(从左到右或从右到左) | .leftToRight , .rightToLeft |
deviceOrientation | 当前设备的方向 | .unknown , .portrait , .portraitUpsideDown , .landscapeLeft , .landscapeRight , .faceUp , .faceDown |
presentationMode | 当前视图的呈现模式 | presentationMode.wrappedValue.dismiss() |
dismiss | 获取“关闭当前视图”的方法 | dismiss() |
undoManager | 当前视图的撤销管理器 | UndoManager() |
redactionReasons | 当前视图的隐蔽理由 | .placeholder , .privacy |
editMode | 当前编辑模式的状态 | .inactive , .active , .transient |
编辑模式可以代表一个页面是否处于编辑状态;您可以通过绑定设置编辑模式,也可以配合 EditButton 按钮来自动完成此操作。即点击 EditButton 的时候,就会将 editMode 的状态改变。 | ||
scenePhase | 当前应用场景的生命阶段(活动、非活动或后台) | .active , .inactive , .background |
openURL | 获取“在Safari应用中打开 URL” 的方法 | openURL(URL(string: "<https://www.apple.com>")!) |
managedObjectContext | Core Data 的托管对象上下文 | NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) |
SwiftUI 的 @Entry
宏使为环境创建自定义值变得简单,具体做法如下
https://www.hackingwithswift.com/quick-start/swiftui/how-to-create-and-use-custom-environment-values