首页 > 解决方案 > 属性包装器和 SwiftUI 环境:属性包装器如何访问其封闭对象的环境?

问题描述

SwiftUI 附带的@FetchRequest属性包装器有助于声明在 Core Data 存储更改时自动更新的属性。你只需要提供一个获取请求:

struct MyView: View {
    @FetchRequest(fetchRequest: /* some fetch request */)
    var myValues: FetchedResults<MyValue>
}

没有托管对象上下文,获取请求无法访问存储。这个上下文必须在视图的环境中传递。

现在我很困惑。

是否有任何公共 API 允许属性包装器访问其封闭对象的环境,或者让 SwiftUI 将此环境提供给属性包装器?

标签: swiftswiftui

解决方案


我们不知道 SwiftUI 的具体实现方式,但我们可以根据现有信息做出一些有根据的猜测。

首先,@propertyWrappers不会从其包含的结构/类中自动访问任何类型的上下文。您可以查看规范以获取证据。这在进化过程中被讨论过几次,但没有被接受。

因此,我们知道框架必须在运行时发生一些事情才能将@EnvironmentObject(这里是NSManagedObjectContext)注入@FetchRequest. 有关如何通过MirrorAPI 执行此类操作的示例,您可以在此问题中查看我的答案。(顺便说一句,之前写的那个@Property是可用的,所以具体的例子不再有用了)。

然而,这篇文章提出了一个示例实现@State并推测(基于程序集转储),SwiftUI 不使用 Mirror API,而是使用TypeMetadata来提高速度:

无镜反射

还有一种方法可以在不使用 Mirror 的情况下获取字段。它使用元数据。

元数据具有字段描述符,其中包含该类型字段的访问器。可以通过使用它来获取字段。

我的各种实验结果 AttributeGraph.framework 在内部使用元数据。AttributeGraph.framework 是 SwiftUI 在内部用于构建 ViewGraph 的私有框架。

您可以通过框架的符号看到它。

$ nm /System/Library/PrivateFrameworks/AttributeGraph.framework/AttributeGraph 符号列表中有 AG::swift::metadata_visitor::visit_field。我没有分析整个汇编代码,但顾名思义,AttributeGraph 使用访问者模式来解析元数据。


推荐阅读