当前位置: 首页 > 科技观察

SwiftUI属性包装器如何处理结构

时间:2023-03-18 22:03:35 科技观察

转载本文请联系网络开发公众号。您已经了解了SwiftUI如何使用@State属性包装器将更改的数据存储在结构中,如何使用$将状态绑定到UI控件的值,以及如何在您更改包装的属性时自动让SwiftUI回调@state我们结构的body属性。所有这些结合起来让我们可以编写这样的代码:in:0...20)}}}如果你执行这段代码,你会发现左右拖动滑块调整文本标签的模糊量完全符合预期。现在,假设我们希望这个绑定做的不仅仅是处理模糊的半径。也许我们想将它保存到UserDefaults中,运行一个方法,或者只是打印出调试的值。您可以尝试像这样更新属性:@StateprivatevarblurAmount:CGFloat=0{didSet{print("Newvalueis\(blurAmount)")}}如果您运行该代码,您会感到失望:当您拖动滑块时,您将会看到模糊量的变化,但您不会看到我们的print()语句被触发——事实上,不会有任何输出。为了理解这里发生了什么,我想让你想想我们正在用CoreData做什么:我们使用@FetchRequest属性包装器查询我们的数据,但我也向你展示了如何直接使用FetchRequest结构,这样我们就可以更好地控制它的创建方式。属性包装器有这个名字,因为它们将我们的属性包装在另一个结构中。对于许多属性包装器,此结构与包装器本身具有相同的名称,但在使用@FetchRequest时,我向您展示了我们实际上如何读取其中的包装值-获取的结果,而不是请求本身。这意味着当我们使用@State来包装一个字符串时,我们最终得到的实际属性类型是State。类似地,当我们将@Environment与其他环境一起使用时,我们最终会得到一个类型为Environment的结构,其中包含一些其他值。之前我解释过我们不能修改视图中的属性,因为它们是结构,因此是固定的。但是,现在您知道@State本身会生成一个结构,所以我们面临一个难题:我该如何修改该结构?Xcode有一个非常有用的命令,称为“快速打开”(使用Cmd+Shift+O访问),它允许您定位项目中的任何文件或类型或导入的任何框架。现在激活它,然后输入“State”——希望第一个结果在它下面显示SwiftUI,但如果没有,找到它并选择它。您将进入SwiftUI生成的界面,这基本上是SwiftUI呈现给我们的所有部分。那里没有实现代码,只有很多协议、结构、修饰符等的定义。我们要求查看状态,所以你应该被带到这一行:@propertyWrapperpublicstructState:DynamicProperty{@propertyWrapper属性使它成为一个@State我们使用。现在往下看几行,您应该看到以下内容:publicvarwrappedValue:Value{getNonMutatingSet}包装的值是我们要存储的实际值,例如字符串。这个生成的接口告诉我们属性可以被读取(获取)和写入(设置),但是当我们设置值时,它实际上并没有改变结构本身。在幕后,它将值发送到SwiftUI以存储在可自由修改的位置,因此结构本身永远不会改变。现在你知道了所有这些,让我们回到我们的问题代码:@StateprivatevarblurAmount:CGFloat=0{didSet{print("Newvalueis\(blurAmount)")}}从表面上看,状态显示为“当blurAmount改变时,打印出它的新值。“但由于@State实际上包装了它的内容,它实际上是在说,当包装blurAmount的State结构发生变化时,打印出新的blurAmount。还在这里吗?现在让我们更进一步:你已经看到State如何用一个不可变的setter,这意味着blurAmount和包装它的State结构都不会改变——我们的绑定直接改变了内部存储的值,这意味着属性观察者永远不会被触发。那么我们如何修复它——我们如何将一些功能附加到包装属性?为此,我们需要自定义绑定-让我们看看接下来...>翻译自Howpropertywrappersbecomestructs[1]References[1]Howpropertywrappersbecomestructs:https://www.hackingwithswift.com/books/ios-swiftui/how-property-wrappers-become-structs