美文网首页
SwiftUI-Persistent storage

SwiftUI-Persistent storage

作者: xiaofu666 | 来源:发表于2023-03-10 18:49 被阅读0次

    持久存储

    存储数据以供应用程序的跨会话使用。

    操作系统提供了在应用程序关闭时存储数据的方法,这样当人们稍后再次打开您的应用程序时,他们可以不间断地继续工作。您使用的机制取决于您需要存储的内容和存储多少等因素,您需要对数据进行序列化还是随机访问,等等。

    您在SwiftUI应用程序中使用与任何其他应用程序中使用的存储类型相同。例如,您可以使用File界面访问磁盘上的文件。然而,SwiftUI还提供了便利,使其更容易在声明性环境中使用某些类型的持久存储。例如,您可以使用FetchFetched与核心数据模型进行交互。

    在应用程序启动时保存状态

    func defaultAppStorage(UserDefaults) -> some View
    视图中包含的App使用的默认存储。
    
    struct AppStorage
    反映User值的属性包装类型,并使该用户默认值更改的视图无效。
    
    struct SceneStorage
    读取和写入持久化的每个场景存储的属性包装器类型。
    

    访问核心数据

    var managedObjectContext: NSManagedObjectContext
    struct FetchRequest
    从核心数据持久存储中检索实体的属性包装器类型。
    
    struct FetchedResults
    从核心数据存储中检索的结果集合。
    
    struct SectionedFetchRequest
    一种属性包装器类型,从核心数据持久存储中检索分组为部分的实体。
    
    struct SectionedFetchResults
    从核心数据持久存储中检索的结果集合,分组为几个部分。
    

    使用SwiftUI恢复应用程序的状态

    通过保留用户的当前活动,为用户提供应用程序的连续性。
    Demo下载

    这个SwiftUI示例项目演示了如何保留应用程序的状态信息,并在后续启动时将应用程序恢复到之前的状态。在后续启动期间,将界面恢复到之前的交互点为用户提供了连续性,并让他们快速完成活动任务。
    使用应用程序时,用户会执行影响用户界面的操作。例如,用户可能会查看特定信息页面,在用户离开应用程序后,操作系统可能会终止它以释放它持有的资源。用户可以返回到他们中断的地方——UI状态恢复是使这种体验无缝的核心部分。
    此示例应用程序演示了在系统中断应用程序的场景中使用状态保存和恢复。示例项目管理一组产品。每个产品都有一个标题、一个图像和其他元数据,您可以查看和编辑。该项目展示了如何在DetailView中保存和恢复产品。

    使用场景存储

    SwiftUI具有“存储场景数据”或Scene的概念。场景存储的操作类似于State,是一种由键/值对组成的属性包装类型。该密钥使系统能够正确保存和恢复值。该值必须是plist类型,因此系统可以正确保存和恢复它。iOS使用键/值摄取此场景存储,然后读取和写入持久化的每个场景存储。操作系统代表用户管理保存和恢复场景存储。后台场景存储的底层数据不能直接获得,因此应用程序必须通过@Scene属性包装器访问它。操作系统不保证数据将保留的时间和频率。场景存储中的数据不一定等同于应用程序的数据模型。场景存储旨在数据模型一起使用。归根结底,将场景存储视为“场景范围的状态”。不要将场景存储与敏感数据一起使用。

    每个需要自己状态保存的视图都实现了@Scene属性包装器。例如,Content使用一个来恢复所选产品:

    @SceneStorage("ContentView.selectedProduct") private var selectedProduct: String?
    

    DetailView使用一个来恢复其当前选定的选项卡:

    @SceneStorage("DetailView.selectedTab") private var selectedTab = Tabs.detail
    

    笔记
    每个场景存储密钥必须是唯一的,并且正确定位到应用程序内的区域或使用。由于此场景存储是应用程序的本地,因此没有必要用应用程序的捆绑标识符作为前缀。在需要的地方使用一些消除歧义的前缀,以确保其唯一性。

    使用活动对象恢复应用程序状态

    NSUser对象捕获应用程序在当前时刻的状态。例如,包括有关应用程序当前显示的数据的信息。系统保存提供的对象,并在下次启动时将其返回给应用程序。当用户关闭应用程序或应用程序进入后台时,示例会创建一个新的NSUser对象。

    每个想要为交接、Spotlight等宣传NSUserSwiftUI视图都必须指定一个userActivity(_:isActive:_:)视图修饰符来宣传NSUseractivity参数是用户活动的类型,is参数指示是否宣传了指定类型的用户活动(此参数默认为true),以及它是否使用指定的处理程序来填充用户活动内容。用户活动的范围仅适用于视图所在的场景或窗口。多个视图可以通告相同的活动类型,处理程序都可以为用户活动的内容做出贡献。请注意,只有isActive参数为trueuserActivity视图修饰符才会调用处理程序。如果没有userActivity视图修饰符指定为活动为真,则iOS将不会公布用户活动。

    每个想要处理传入的NSUserSwiftUI视图必须指定一个onActivity(_:perform:)视图修饰符。当视图收到视图所在的场景或窗口的指定活动类型时,这需要调用NSUser类型和处理程序。

    .onContinueUserActivity(DetailView.productUserActivityType) { userActivity in
        if let product = try? userActivity.typedPayload(Product.self) {
            selectedProduct = product.id.uuidString
        }
    }
    

    测试状态恢复

    此示例恢复了以下用户界面:

    • 详细信息视图控制器—在集合视图中点击产品以打开其详细信息。该应用程序恢复所选产品和所选选项卡。
    • 详细信息视图控制器的编辑状态—在详细信息视图中,点击编辑。该应用程序恢复编辑视图及其内容。
    • 次要窗口—(仅限iPad)将产品从集合视图拖到设备屏幕的左侧或右侧,以创建第二个场景窗口。该应用程序恢复了该场景及其产品。

    状态恢复可以在设备和模拟器上进行测试。调试示例项目时,当用户强制退出应用程序时,系统会自动删除其保留状态。删除保留状态信息是一种安全预防措施。此外,如果此应用程序在启动时崩溃,系统也会删除保留的状态。

    要测试示例应用程序恢复示例状态的能力,不要在调试期间使用应用程序切换器强制退出。相反,使用Xcode停止应用程序或以编程方式停止应用程序。另一种技术是使用主屏幕按钮暂停示例应用程序,然后在Xcode中停止调试器。使用Xcode再次启动示例应用程序,SwiftUI启动状态恢复过程。

    要将Spotlight与接力一起使用,请按照以下步骤操作:

    1. 在Xcode中,在on闭包的Detail.swift中设置一个断点。
    2. 运行示例项目。
    3. 在集合视图中点击产品(“Cherries”)以导航到其详细信息。
    4. 从屏幕顶部下拉系统表(以强制聚光灯更新其索引并请求活动)。注意,DetailView userActivity闭包由iOS调用。
    5. 返回应用程序,然后返回集合视图。
    6. 点击樱桃以外的产品(即芒果)。
    7. 通过点击主屏幕按钮暂停应用程序。
    8. 在主屏幕上,向下轻扫以打开“聚焦”窗口。
    9. Spotlight搜索字段中,键入“Cherries”。搜索结果将显示“显示樱桃产品”。
    10. 点击它。注意,调用了DetailView onContinueUserActivity闭包。DetailView将显示Cherries产品。

    加载和显示大型数据源

    在后台消耗数据,并通过批处理导入和防止重复记录来降低内存使用。

    Demo下载

    该示例创建了一个应用程序,显示过去30天内美国通过消费U记录的地震列表。S.地质调查局(USGS)实时数据源。

    要加载USGS JSON提要,请执行以下任一操作:

    • 在iOS上,拉动以刷新List

    • 在iOS和macOS上,按刷新按钮(⌘R)。

    该应用程序将在URLSession的默认委托队列上加载请求的数据,这是一个在后台运行的操作队列。下载提要并完成会话数据任务后,应用程序继续处理此队列,在不阻止主队列的情况下将大量提要元素导入商店。

    笔记
    这个示例代码项目与WWDC21会话10017相关联:将核心数据并发带到Swift和SwiftUI

    在后台导入数据

    要在后台导入数据,应用程序可以使用一个或两个托管对象上下文。示例使用两个(NSManaged)实例:

    • 向用户界面提供数据的主队列上下文。

    • 在后台队列上执行导入的私有队列上下文。

    这两个上下文都连接到同一个persistent。这种配置比使用嵌套上下文更有效。

    该示例通过使用NSPersistent设置核心数据堆栈来创建主队列上下文,该堆栈在其view属性中初始化主队列上下文。

    let container = NSPersistentContainer(name: "Earthquakes")
    

    通过调用持久容器的newContext()方法创建私有队列上下文。

    let taskContext = container.newBackgroundContext()
    

    当提要下载完成后,示例使用任务上下文在后台消耗提要。在Core Data中,每个基于队列的上下文都有自己的串行队列,应用程序必须通过用perform(_:)包装代码来序列化与队列一起操作上下文的任务——带或不带await关键字——orperformAndWaitWait(_:)闭包。

    try await taskContext.perform {
    

    为了有效地处理大型数据集,示例使用NSBatch直接访问存储——无需与上下文交互、触发任何键值观察或分配托管对象。NSBatch的闭包式初始化器允许应用程序在Core Data调用thedictionaryHandler闭包时一次提供一条记录,这有助于应用程序保持低内存占用,因为它们不需要为所有记录准备缓冲区。

    let batchInsertRequest = self.newBatchInsertRequest(with: propertiesList)
    if let fetchResult = try? taskContext.execute(batchInsertRequest),
       let batchInsertResult = fetchResult as? NSBatchInsertResult,
       let success = batchInsertResult.result as? Bool, success {
        return
    }
    

    合并更改并更新用户界面

    由于NSBatch绕过上下文,并且不会触发NSManaged通知,因此需要通过更改更新UI的应用程序有两个选项:

    • 通过解析商店的持久历史记录来提取相关更改,然后将它们合并到视图上下文中。有关持久性历史记录跟踪的更多信息,请参阅消耗相关商店更改。
    • 从商店重新获取数据。但是,如果视图上下文被固定在查询生成上,则需要在获取数据之前重置上下文。有关查询生成的更多信息,请参阅商店更改时访问数据。

    此示例使用持久存储远程更改通知和持久历史记录跟踪来更新用户界面,因为:

    • 数据模型包含单个实体,因此所有更改都与List相关,不需要解析历史记录中的特定更改。
    • FetchRequest直接从商店获取和检索结果,List会自动刷新其内容。
    • SwiftUI只关注视图上下文,因此Quakes观察NSPersistent通知,将后台上下文中的更改合并,执行批处理操作到视图上下文中。

    通过将存储描述上的NSPersistentStoreRemoteChangeNotification选项设置为true,为持久存储启用远程更改通知。

    description.setOption(true as NSNumber,
                          forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
    

    通过将NSPersistent选项设置为true,为持久存储启用持久性历史记录跟踪。

    description.setOption(true as NSNumber,
                          forKey: NSPersistentHistoryTrackingKey)
    

    每当持久存储内发生更改时,包括其他进程的写入,存储都会发布远程更改通知。当样本收到通知时,它会获取给定令牌之后发生的持久历史事务和更改。在持久历史记录更改请求检索历史记录后,示例通过mergeChanges(fromSave:)将每个事务的objectIDNotification()合并到视图上下文中。

    let changeRequest = NSPersistentHistoryChangeRequest.fetchHistory(after: self.lastToken)
    let historyResult = try taskContext.execute(changeRequest) as? NSPersistentHistoryResult
    if let history = historyResult?.result as? [NSPersistentHistoryTransaction],
       !history.isEmpty {
        self.mergePersistentHistoryChanges(from: history)
        return
    }
    

    执行每个NSBatchNSBatch后,示例将任何UI更新发送回主队列,以在SwiftUI中呈现它们。

    let viewContext = container.viewContext
    viewContext.perform {
        for transaction in history {
            viewContext.mergeChanges(fromContextDidSave: transaction.objectIDNotification())
            self.lastToken = transaction.token
        }
    }
    

    合并上次事务的更改后,示例需要将令牌存储在内存或磁盘上,以便在随后的持久历史更改请求中使用它。

    批量工作以降低内存占用空间

    当应用程序在上下文中获取或创建对象时,Core Data会缓存该对象,以避免在应用程序再次使用这些对象时往返存储文件。然而,这种方法增加了应用程序的内存占用空间,因为它处理了越来越多的对象,并最终可能导致iOS上的低内存警告或应用程序终止。NSBatch不会明显增加应用程序的内存占用,因为它不会将数据加载到内存中。

    笔记
    旨在在iOS 13或macOS 10.15之前的系统上运行的应用程序需要通过批量处理对象并调用reset()在每次批处理后重置上下文来避免内存足迹增加。

    示例将viewautomaticallyMerges属性设置为false,以防止每次保存后台上下文时Core Data自动合并更改。

    container.viewContext.automaticallyMergesChangesFromParent = false
    

    防止商店中重复数据

    每次示例应用程序重新加载JSON提要时,解析的数据都会包含过去一个月的所有地震记录,因此它可以重复许多已导入的数据。为了避免创建重复的记录,该应用程序限制属性或属性组合在所有实例中都是唯一的。

    code属性唯一标识地震记录,因此在code上约束Quake实体可确保没有两个存储的记录具有相同的code值。

    在数据模型编辑器中选择Quake实体。在数据模型检查器中,通过单击约束列表下的+按钮来添加新的约束。出现一个约束占位符。

      comma, separated, properties
    

    双击占位符进行编辑。输入属性的名称,或以逗号分隔的属性列表,作为实体的唯一约束。

      code
    

    保存新记录时,存储现在会检查是否已存在任何具有约束属性相同值的记录。在发生冲突的情况下,NSMergeByProperty策略将发挥作用,新记录覆盖现有记录中的所有字段。

    container.viewContext.automaticallyMergesChangesFromParent = false
    

    FetchRequest

    从核心数据持久存储中检索实体的属性包装器类型。

    @propertyWrapper @MainActor struct FetchRequest<Result> where Result : NSFetchRequestResult
    

    使用Fetch属性包装器声明Fetched属性,该属性为SwiftUI视图提供核心数据托管对象的集合。请求从您指定的结果占位符类型中推断实体类型。使用可选谓词和排序描述符来条件请求。例如,您可以创建一个请求,列出加载和显示大型数据提要示例代码项目定义的所有Quake管理对象,以存储地震数据,按其time属性排序:

    @FetchRequest(sortDescriptors: [SortDescriptor(\.time, order: .reverse)])
    private var quakes: FetchedResults<Quake> // Define Quake in your model.
    

    或者,当您需要更多灵活性时,您可以使用配置的NSFetch实例初始化请求:

    @FetchRequest(fetchRequest: request)
    private var quakes: FetchedResults<Quake>
    

    始终将具有获取请求包装的属性声明为私有。这使编译器帮助您避免意外地从封闭视图的成员初始化器中设置属性。

    获取请求及其结果使用存储在环境中的托管对象上下文,您可以使用managedObjectContext环境值访问该上下文。为了支持用户界面活动,您通常依赖共享NSPersistent实例的view属性。例如,您可以使用作为模型一部分定义的共享容器在顶级内容视图上设置上下文:

    ContentView()
        .environment(
            \.managedObjectContext,
            QuakesProvider.shared.container.viewContext)
    

    当您需要动态更改谓词或排序描述符时,请访问请求的Fetch.Configuration结构。要创建请求,根据它们共享的特征对获取的结果进行分组,请改用Sectioned

    init(sortDescriptors: [SortDescriptor<Result>], predicate: NSPredicate?, animation: Animation?)
    基于谓词和值类型排序参数创建获取请求。
    当Result继承NSManaged时可用。
    
    init(sortDescriptors: [NSSortDescriptor], predicate: NSPredicate?, animation: Animation?)
    基于谓词和引用类型排序参数创建获取请求。
    当Result继承NSManaged时可用。
    
    init(entity: NSEntityDescription, sortDescriptors: [NSSortDescriptor], predicate: NSPredicate?, animation: Animation?)
    基于谓词和排序参数,为指定的实体描述创建获取请求。
    当Result符合NSFetch时可用。
    
    init(fetchRequest: NSFetchRequest<Result>, animation: Animation?)
    创建一个完全配置的获取请求,在更新结果时使用指定的动画。
    当Result符合NSFetch时可用。
    
    init(fetchRequest: NSFetchRequest<Result>, transaction: Transaction)
    创建一个完全配置的获取请求,在更新结果时使用指定的事务。
    当Result符合NSFetch时可用。
    
    struct Configuration
    请求的可配置属性。
    
    var projectedValue: Binding<FetchRequest<Result>.Configuration>
    对请求的可变配置属性的绑定。
    
    var wrappedValue: FetchedResults<Result>
    获取请求的获取结果。
    

    FetchedResults

    从核心数据存储中检索的结果集合。

    struct FetchedResults<Result> where Result : NSFetchRequestResult
    

    使用Fetched实例在应用程序的用户界面中显示或编辑Core Data托管对象。您通过指定Result类型作为实体类型,并使用Fetch属性包装器注释获取的结果属性声明来请求一组特定的结果。例如,您可以创建一个请求,列出加载和显示大型数据提要示例代码项目定义的所有Quake管理对象,以存储地震数据,按其time属性排序:

    @FetchRequest(sortDescriptors: [SortDescriptor(\.time, order: .reverse)])
    private var quakes: FetchedResults<Quake>
    

    结果实例符合RandomAccessCollection,因此您可以像访问任何其他集合一样访问它。例如,您可以创建一个迭代所有结果的List

    List(quakes) { quake in
        NavigationLink(destination: QuakeDetail(quake: quake)) {
            QuakeRow(quake: quake)
        }
    }
    

    当您需要动态更改请求的谓词或排序描述符时,请分别设置结果实例的nssortns属性。
    获取请求及其结果使用存储在环境中的托管对象上下文,您可以使用managedObjectContext环境值访问该上下文。为了支持用户界面活动,您通常依赖共享NSPersistent实例的view属性。例如,您可以使用作为模型的一部分定义的容器在顶级内容视图上设置上下文:

    ContentView()
        .environment(
            \.managedObjectContext,
            QuakesProvider.shared.container.viewContext)
    
    var nsPredicate: NSPredicate?
    请求的谓词。
    
    var sortDescriptors: [SortDescriptor<Result>]
    请求的排序描述符,作为值类型访问。
    当Result继承NSManaged时可用。
    
    var nsSortDescriptors: [NSSortDescriptor]
    请求的排序描述符,作为引用类型访问。
    
    var startIndex: Int
    结果集合中第一个实体的索引。
    
    var endIndex: Int
    比最后一个有效下标参数大一个的索引。
    
    subscript(Int) -> Result
    获取指定索引处的实体。
    

    支持类型

    typealias Element
    表示序列元素的类型。
    
    typealias Index
    表示集合中位置的类型。
    
    typealias Indices
    一种类型,以升序表示可用于下标集合的索引。
    
    typealias Iterator
    提供集合迭代接口并封装其迭代状态的类型。
    
    typealias SubSequence
    代表该集合元素的连续子范围的集合。子序列与原始集合共享索引。
    

    SectionedFetchRequest

    一种属性包装器类型,从核心数据持久存储中检索分组为部分的实体。

    @propertyWrapper @MainActor struct SectionedFetchRequest<SectionIdentifier, Result> where SectionIdentifier : Hashable, Result : NSFetchRequestResult
    

    使用SectionedFetchRequest属性包装器声明SectionedFetchResults属性,该属性向SwiftUI视图提供核心数据管理对象的分组集合。如果不需要分段,请改用FetchRequest

    使用可选谓词和排序描述符配置分段获取请求,并包含一个section参数来指示如何对获取的结果进行分组。确保您选择协同工作的排序和分区,以避免不连续的分区。例如,您可以请求一个地震列表,由加载和显示大型数据源示例代码项目定义的Quake管理对象组成,以存储地震数据,按时间排序并按日期分组:

    @SectionedFetchRequest<String, Quake>(
        sectionIdentifier: \.day,
        sortDescriptors: [SortDescriptor(\.time, order: .reverse)]
    )
    private var quakes: SectionedFetchResults<String, Quake>
    

    始终将具有分段获取请求包装的属性声明为私有。这使编译器帮助您避免意外地从封闭视图的成员初始化器中设置属性。

    请求从您指定的结果类型中推断出实体类型,即上述示例中的Quake。指示一个Section类型,以声明在获取对象的section键路径中找到的类型。节标识符类型必须符合Hashable协议。

    上面的示例取决于具有存储或计算字符串的day属性的Quake类型。请务必用@objc属性标记任何计算属性,使其作为部分标识符。为了获得大型数据集的最佳性能,请使用存储的属性。

    分段获取请求及其结果使用存储在环境中的托管对象上下文,您可以使用managedObjectContext环境值访问该上下文。为了支持用户界面活动,您通常依赖共享的NSPersistent实例的view属性。例如,您可以使用作为模型的一部分定义的共享容器在顶级内容视图上设置上下文:

    ContentView()
        .environment(
            \.managedObjectContext,
            QuakesProvider.shared.container.viewContext)
    

    当您需要动态更改节标识符、谓词或排序描述符时,请直接或绑定访问请求的Sectioned.Configuration结构。

    创建获取请求

    init(sectionIdentifier: KeyPath<Result, SectionIdentifier>, sortDescriptors: [SortDescriptor<Result>], predicate: NSPredicate?, animation: Animation?)
    基于节标识符、谓词和值类型排序参数创建分段获取请求。
    当Section符合Hashable和Result继承NSManaged时可用。
    
    init(sectionIdentifier: KeyPath<Result, SectionIdentifier>, sortDescriptors: [NSSortDescriptor], predicate: NSPredicate?, animation: Animation?)
    根据节标识符、谓词和引用类型排序参数创建分段获取请求。
    当Section符合Hashable和Result继承NSManaged时可用。
    
    init(entity: NSEntityDescription, sectionIdentifier: KeyPath<Result, SectionIdentifier>, sortDescriptors: [NSSortDescriptor], predicate: NSPredicate?, animation: Animation?)
    根据节标识符、谓词和排序参数,为指定的实体描述创建分段获取请求。
    当Section符合Hashable,Result符合NSFetch时可用。
    

    创建完全配置的获取请求

    init(fetchRequest: NSFetchRequest<Result>, sectionIdentifier: KeyPath<Result, SectionIdentifier>, animation: Animation?)
    创建一个完全配置的分段获取请求,在更新结果时使用指定的动画。
    当Section符合Hashable,Result符合NSFetch时可用。
    
    init(fetchRequest: NSFetchRequest<Result>, sectionIdentifier: KeyPath<Result, SectionIdentifier>, transaction: Transaction)
    创建一个完全配置的分段获取请求,在更新结果时使用指定的事务。
    当Section符合Hashable,Result符合NSFetch时可用。
    

    动态配置请求

    struct Configuration
    请求的可配置属性。
    
    var projectedValue: Binding<SectionedFetchRequest<SectionIdentifier, Result>.Configuration>
    对请求的可变配置属性的绑定。
    

    获取已获取的结果

    var wrappedValue: SectionedFetchResults<SectionIdentifier, Result>
    获取请求的获取结果。
    

    SectionedFetchResults

    从核心数据持久存储中检索的结果集合,分组为几个部分。

    struct SectionedFetchResults<SectionIdentifier, Result> where SectionIdentifier : Hashable, Result : NSFetchRequestResult
    

    使用SectionedFetchResults实例在应用程序的用户界面中显示或编辑Core Data托管对象,这些对象分组为部分。如果您不需要切片,请改用Fetched

    通过使用SectionedFetchRequest属性包装器注释获取的结果属性声明,可以请求一组特定的结果。用Results类型指示提取的实体的类型,以及用SectionIdentifier类型区分节的标识符的类型。例如,您可以创建一个请求,列出Loading and Displaying a Large Data Feed示例代码项目定义的用于存储地震数据的所有地震管理对象,这些对象按时间属性排序,并按表示地震发生日期的字符串分组:

    @SectionedFetchRequest<String, Quake>(
        sectionIdentifier: \.day,
        sortDescriptors: [SortDescriptor(\.time, order: .reverse)]
    )
    private var quakes: SectionedFetchResults<String, Quake>
    

    quakes属性充当Sectioned.Section实例的集合,每个实例都包含Quake实例的集合。上面的示例取决于声明存储或计算timeday属性的Quake模型对象。为了获得大型数据集的最佳性能,请使用存储的属性。

    节的集合以及每个节中的托管对象的集合都符合RandomAccessCollection协议,因此您可以像访问任何其他集合一样访问它们。例如,您可以在List创建嵌套的For循环来迭代结果:

    List {
        ForEach(quakes) { section in
            Section(header: Text(section.id)) {
                ForEach(section) { quake in
                    QuakeRow(quake: quake) // Displays information about a quake.
                }
            }
        }
    }
    

    不要将用于创建分层显示的Section视图与保存获取结果的SectionedFetchResults.Section实例混淆。

    当您需要动态更改请求的节标识符、谓词或排序描述符时,请分别设置结果实例的section、ns和sort或ns属性。确保排序和分段一起工作,以避免不协调的部分。

    获取请求及其结果使用存储在环境中的托管对象上下文,您可以使用managedObjectContext环境值访问该上下文。为了支持用户界面活动,您通常依赖共享NSPersistent实例的view属性。例如,您可以使用定义为模型一部分的容器在顶级内容视图上设置上下文:

    ContentView()
        .environment(
            \.managedObjectContext,
            QuakesProvider.shared.container.viewContext)
    

    配置关联的分段获取请求

    var nsPredicate: NSPredicate?
    请求的谓词。
    
    var sortDescriptors: [SortDescriptor<Result>]
    请求的排序描述符,作为值类型访问。
    当Section符合Hashable和Result继承NSManaged时可用。
    
    var nsSortDescriptors: [NSSortDescriptor]
    请求的排序描述符,作为引用类型访问。
    
    var sectionIdentifier: KeyPath<Result, SectionIdentifier>
    系统用于将获取的结果分组到部分的关键路径。
    
    struct Section
    共享指定标识符的已获取结果的集合。
    

    获取指数

    var startIndex: Int
    结果集合中第一部分的索引。
    
    var endIndex: Int
    比上一节大一个的索引。
    

    获得结果

    subscript(Int) -> SectionedFetchResults<SectionIdentifier, Result>.Section
    获取指定索引处的部分。
    

    支持类型

    typealias Element
    表示序列元素的类型。
    
    typealias Index
    表示集合中位置的类型。
    
    typealias Indices
    一种类型,以升序表示可用于下标集合的索引。
    
    typealias Iterator
    提供集合迭代接口并封装其迭代状态的类型。
    
    typealias SubSequence
    代表该集合元素的连续子范围的集合。子序列与原始集合共享索引。
    

    相关文章

      网友评论

          本文标题:SwiftUI-Persistent storage

          本文链接:https://www.haomeiwen.com/subject/lerjldtx.html