【问题标题】:Swift Core Data - storing an array of custom typesSwift Core Data - 存储自定义类型的数组
【发布时间】:2020-09-18 15:09:13
【问题描述】:

我正在尝试创建一个数据模型,它反映了我用来处理 API 调用的视图模型,我的想法是我将能够将所有必要的数据存储在核心数据中,然后在用户访问时访问它离线,有效地为应用提供离线功能。

但是,我需要存储一个实体,它是我在应用程序中拥有的自定义类的数组:

[OrderSheet]

这是一个结构体,定义如下:

struct OrderSheet {
    let order: SheetClass // codable class
    let sheet: Sheet // codable struct

    init(fuelOrder: SheetClass, sheet: Sheet) {
    self.order = order
    self.sheet = sheet
    }
}

如何创建能够存储上述内容的实体?

【问题讨论】:

  • 为 OrderSheet、Sheet 和 SheetClass 创建 3 个实体
  • 或者只创建两个实体,Sheet 和 SheetClass,它们之间具有多对多关系(这似乎是 OrderSheet 所代表的)。

标签: swift xcode core-data struct


【解决方案1】:

一种简单的方法是拥有一个仅包含一个 Data 字段(xcdatamodel 设置中的二进制数据)的实体,这将是 orderSheet 本身。

在采用这种解决方案之前,我想提一下,这种方法的一个缺点是;如果将来稍后,OrderSheet 中的任何模型发生更改,您将无法检索已存储的对象,因为转换将失败。解决此问题的一种方法是将OrderSheet 和子模型中的所有内容声明为可选。但是,如果它不是那么重要,也就是说,如果在应用程序更新后无法读取用户设备上的旧模型是可以的,(也许它们将被新的网络调用替换)那么你可以不将属性标记为可选.

假设您创建了一个名为 OrderSheetManaged 的实体,其中包含一个字段,如下所示:

import Foundation
import CoreData

@objc(Entity)
public class OrderSheetManaged: NSManagedObject {

}

extension OrderSheetManaged {
    @nonobjc public class func fetchRequest() -> NSFetchRequest<OrderSheetManaged> {
        return NSFetchRequest<OrderSheetManaged>(entityName: "OrderSheetManaged")
    }
    @NSManaged public var orderSheet: Data?
}

我将为 NSManagedObjectContext 编写一些代码,这与您的问题没有直接关系,如果您不熟悉它,您应该研究如何从中初始化核心数据堆栈和托管上下文,因为它很重要。

为了简单起见,我还做了一些强制展开,确保不要在生产代码中不需要的地方强制展开。

现在,只要您有一个实际的 OrderSheet 对象(在我下面的示例中是 orderSheet),并且之前已解析过,您将其转换为 Data 并使用新的 Core Data 模型将其持久化,如下所示:

// unrelated to question, it should already be initialised from core data stack, I just init with
// concurrency type to make compiler happy, dont do this before further research.
let yourManagedContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
let entityDescription = NSEntityDescription.entity(forEntityName: "OrderSheetManaged",
                                                   in: yourManagedContext)

let dataForCoreData = try! JSONEncoder().encode(orderSheet)

let managedOrderSheet = NSManagedObject(entity: entityDescription!, insertInto: yourManagedContext)
managedOrderSheet.setValue(dataForCoreData, forKey: "orderSheet")

现在我们已将您的对象作为数据保存在包装器核心数据模型中 (OrderSheetManaged)

现在让我们看看如何从核心数据中获取这些模型并将其转换回 OrderSheet 模型:

// when you fetch it
var orderSheets = [OrderSheet]()
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "OrderSheetManaged")
var coreDataObjects: [NSManagedObject]!
do {
    coreDataObjects = try yourManagedContext.fetch(request) as? [NSManagedObject]

    for coreDataObject in coreDataObjects {
        if let orderSheetData = coreDataObject.value(forKey: "orderSheet") as? Data {
            let orderSheet = try! JSONDecoder().decode(OrderSheet.self, from: orderSheetData)
            orderSheets.append(orderSheet)
        }
    }
} catch {
    error
}

现在您将在 orderSheets 数组中保存所有存储的订单。

您还可以编写一些实用方法来轻松修改核心数据模型,方法是先将其中的orderSheet 数据转换为OrderSheet,然后在修改后再次将其转换回Data,然后再次使用setValue 持久化.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-30
    • 1970-01-01
    • 2015-05-15
    相关资源
    最近更新 更多