属性包装器和SwiftUI环境:属性包装器如何访问其封闭对象的环境?

时间:2019-08-27 06:45:04

标签: swift swiftui

SwiftUI附带的@FetchRequest属性包装器有助于声明每当核心数据存储发生更改时自动更新的属性。您只需提供获取请求:

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

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

现在我很困惑。

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

1 个答案:

答案 0 :(得分:2)

我们不知道SwiftUI如何实现的确切内部原理,但是我们可以根据已有的信息做出一些有根据的猜测。

首先,@propertyWrapper不会从其包含的struct / class中自动访问任何种类的上下文。您可以查看the spec来证明这一点。在进化过程中对此进行了几次讨论,但未被接受。

因此,我们知道框架在运行时必须发生某些事情,才能将@EnvironmentObject(此处为NSManagedObjectContext)注入到@FetchRequest中。有关如何通过Mirror API进行类似操作的示例,您可以查看my answer in this question。 (顺便说一句,它是在@Property可用之前编写的,因此特定示例不再有用。)

但是,this article建议使用@State的示例实现,并推测(基于 程序集转储),而不是使用Mirror API,SwiftUI使用TypeMetadata来提高速度:

  

无镜反射

     

仍有一种无需使用镜像即可获取字段的方法。它正在使用元数据。

     

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

     

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

     

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

     

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