dea*_*rne 12 optional swift swiftui
我是这样使用的@EnvironmentObject
:
struct MyView: View {
@EnvironmentObject var object: MyObject
...
}
Run Code Online (Sandbox Code Playgroud)
但我的代码不需要为object
.
只是使这个可选不起作用(甚至不编译 - Property type 'MyObject?' does not match that of the 'wrappedValue' property of its wrapper type 'EnvironmentObject'
)
您也不能传入默认对象(这也可以解决我的问题) - 作为属性的初始值,或作为@EnvironmentObject
. ei 这些不起作用:
@EnvironmentObject var object: MyObject = MyObject()
@EnvironmentObject(MyObject()) var object: MyObject
Run Code Online (Sandbox Code Playgroud)
我试图将 包装@EnvironmentObject
在我自己的属性包装器中,但这根本不起作用。
我也试过包装对 object 属性的访问,但它不会抛出一个可以被捕获的异常,它会抛出一个fatalError
.
有什么我遗漏的吗,或者我只是在尝试不可能的事情?
Mam*_*yya 12
通过符合EnvironmentKey
您的要求,基本上可以提供一个默认值,SwiftUI 可以在丢失的情况下安全地回退到该默认值。此外,您还可以EnvironmentValues
通过基于关键路径的 API 来访问对象。
您可以将两者结合起来,如下所示:
public struct ObjectEnvironmentKey: EnvironmentKey {
// this is the default value that SwiftUI will fallback to if you don't pass the object
public static var defaultValue: Object = .init()
}
public extension EnvironmentValues {
// the new key path to access your object (\.object)
var object: Object {
get { self[ObjectEnvironmentKey.self] }
set { self[ObjectEnvironmentKey.self] = newValue }
}
}
public extension View {
// this is just an elegant wrapper to set your object into the environment
func object(_ value: Object) -> some View {
environment(\.object, value)
}
}
Run Code Online (Sandbox Code Playgroud)
现在从视图访问您的新对象:
struct MyView: View {
@Environment(\.object) var object
}
Run Code Online (Sandbox Code Playgroud)
享受!
ato*_*oil 11
如果 EnvironmentObject 中的任何内容发生变化(和其他警告),它不是很优雅并且很容易中断,但是如果您在 SwiftUI 1 / Xcode 11.3.1 中打印 EnvironmentObject 您会得到:
EnvironmentObject<X>(_store: nil, _seed: 1)
那么怎么样:
extension EnvironmentObject {
var hasValue: Bool {
!String(describing: self).contains("_store: nil")
}
}
Run Code Online (Sandbox Code Playgroud)
我知道您告诉过您无法将对象放入包装器中,但是我认为这个解决方案是实现您想要的效果的好方法。
您唯一要做的就是创建一个非可选的包装器,但它将包含您的可选对象:
class MyObjectWrapper: ObservableObject {
@Published var object: MyObject?
}
Run Code Online (Sandbox Code Playgroud)
然后,创建视图并将包装器分配给环境:
let wrapper = MyObjectWrapper()
// You can try to load your object here, and set it to nil if needed.
let view = MyView().environmentObject(wrapper)
Run Code Online (Sandbox Code Playgroud)
在您看来,您现在可以检查对象是否存在:
struct MyView: View {
@EnvironmentObject var objectWrapper: MyObjectWrapper
var body: some View {
if objectWrapper.object != nil {
Text("Not nil")
} else {
Text("Nil")
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果任何视图发生变化objectWrapper.object
,视图将被重新加载。
您可以轻松模拟您的视图,甚至可以在几秒钟后触发更改以检查转换:
struct MyView_Previews: PreviewProvider {
static var previews: some View {
let objectWrapper = MyObjectWrapper()
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
objectWrapper.object = MyObject()
}
return MyView().environmentObject(objectWrapper)
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3172 次 |
最近记录: |