iOS 核心数据,不获取刚刚更新关系的实体

问题描述 投票:0回答:1

问题: 当我获取一个在同一上下文中更新了关系的实体时,获取请求返回一个 nil。

说明:

数据模式:联系人<--->费用(一对多关系)联系人的“serverId”属性是唯一的,并且由于一些附加规则,我不能在核心数据中使用“约束”,而是使用以下代码。

现在,当从网络响应中插入一系列费用时,我对同一个联系人有多项费用。以下代码返回 nil,即使联系人存在于同一上下文中,如果它有更新。

if let entity = Contact.fetch(serverId: serverId, context: context) {
    return entity
} else {
    return Contact.new(serverId: serverId, context: context)
}

以下是支持的调试器日志:

  • Server id 是我们用作谓词输入的 id。
(lldb) po serverId
55001
  • Coredata fetch 返回 nil
(lldb) po Contact.fetch(serverId: serverId, context: context)
nil
  • 上下文已经知道该对象,因为它刚刚被更新。可以看到更新后的key是一个关系
(lldb) po context.updatedObjects.filter { ($0 as? Entity)?.serverId == serverId }.count
1

(lldb) po context.updatedObjects.filter { ($0 as? Entity)?.serverId == serverId }.first?.changedValues().keys
▿ Optional<Keys>
  ▿ some : Dictionary.Keys(["expenses"])
    ▿ _variant : _Variant
      ▿ object : _BridgeStorage<__RawDictionaryStorage>
        - rawValue : (Opaque Value)
  • 重置上下文后获取实体。
(lldb) po context.reset()
0 elements

(lldb) po Contact.fetch(serverId: serverId, context: context)
▿ Optional<Contact>
  - some : <Contact: 0x6000015371b0> (entity: Contact; id: 0xe7984dad6d91badc <x-coredata://593D407B-BF00-4923-980E-FDC7BEBD46C1/Contact/p834>; data: <fault>)

添加了其他详细信息:

实体只是一个协议包装器,下面是一个简化的代码。

protocol Entity {
  var serverId: Int64 { get set }
}

extension Contact: Entity {}

获取实现,重用多个“实体”类型。

extension Entity {

 static func fetch(serverId: Int64, context: NSManagedObjectContext) -> Entity? {
     let predicate = NSPredicate(format: "serverId == '\(String(serverId))'")
    return context.fetch(Entity.self, predicate: predicate)?.first
 }

func fetch<T: NSManagedObject>(_ type: T.Type, predicate: NSPredicate?, sort: [NSSortDescriptor]? = nil) -> [T]? {

  let context = self
  let request = T.fetchRequest()
  if let predicate = predicate {
      request.predicate = predicate
  }
  if let sortDescriptors = sort {
      request.sortDescriptors = sortDescriptors
  }
  
  var results: [NSFetchRequestResult] = []
  
  do {
          results = try context.fetch(request)
      } catch {
          print("Error with request: \(error)")
      }
  
  return results as? [T] ?? []
}


Temp Fix:通过检查当前上下文中的对象添加

if entity == nil, context.hasChanges == true {
           
   entity = context.updatedObjects.first { ($0 as? Entity)?.serverId == serverId } as? Entity

   if entity == nil {
       entity = context.insertedObjects.first { ($0 as? Entity)?.serverId == serverId } as? Entity
   }
}
ios core-data
1个回答
0
投票
(lldb) po context.updatedObjects.filter { ($0 as? Entity)?.serverId == serverId }.count
1

(lldb) po context.updatedObjects.filter { ($0 as? Entity)?.serverId == serverId }.first?.changedValues().keys
▿ Optional<Keys>
  ▿ some :(["expenses"])
    ▿ _variant : _Variant
      ▿ object : _BridgeStorage<__RawDictionaryStorage>
        - rawValue : (Opaque Value)
© www.soinside.com 2019 - 2024. All rights reserved.