ios - MagicalRecord - 保存后数据错误

标签 ios swift core-data magicalrecord

@编辑 @PangHoMing - 我会再次一步一步地做。 首先设置 - 按照您的建议

    MagicalRecord.setLoggingLevel(.verbose)
    MagicalRecord.setupCoreDataStack(withAutoMigratingSqliteStoreNamed: dataStack)

下一个数据保存方法:

     MagicalRecord.save({ (context) in
         _ = data(context)
     }) { (success, error) in
         completion(success,error)
     }

我正在使用CoreDataEditor预览实体。执行完这部分后,一切似乎都很好。

购物车创建闭包(我刚刚删除了负责特定字段的部分以缩短消息)

  let createCart: (NSManagedObjectContext) -> () = {context in
            let offlineCart = Cart.mr_createEntity(in: context)!
            offlineCart.code = "0"

接下来我将取 repo 物车数据以将其返回。也正如您所建议的,不使用特定上下文

    let cart: Cart? = Cart.mr_findFirst()

现在让我们将某物添加到我的购物车,这里开始一些有问题的部分

      let addEntry: (NSManagedObjectContext) -> () = { context in
        if let entry = CartEntry.mr_findFirst(with: NSPredicate(format: "product.code == %@", productCode), in: context) {
            entry.quantity = NSNumber.init(value: (entry.quantity?.intValue)! + 1)
        } else {
            let entry = CartEntry.mr_createEntity(in: context)!
            entry.quantity = quantity
            entry.product = Product.mr_findFirst(with: NSPredicate(format: "code == %@", productCode), in: context)
            entry.code = productCode
            entry.cart = Cart.mr_findFirst(in: context)
        }
    }

正如您所看到的,上面的代码正在尝试查找现有的 CartEntry如果发现它只是增加数量,如果没有则创建新的 CartEntry相关于CartProduct 。为什么会有in: context ?因为当我忽略它们时,保存不会执行。我收到如下警告:NO CHANGES IN ** saveWithBlock:completion: ** CONTEXT - NOT SAVING

到目前为止,一切似乎都还不错。 CoreDataEditor显示这样的结构 CoreDataStructure

现在让我们进行删除操作。

尝试 1 - 删除传递给 save 方法的闭包(如上所述)

        let removeEntry: (NSManagedObjectContext) -> () = { context in
            CartEntry.mr_deleteAll(matching: NSPredicate(format: "product.code == %@", product.code), in: context)
        }

        self.coreDataManager.saveData(data: removeEntry, completion: { (succes, error) in
            completion(succes, error)
        })

效果1: 竣工区 block 返回success = true, error = nil执行此操作后,我们立即刷新购物车 let cart: Cart? = Cart.mr_findFirst() - cart.entries 字段有 2 CartEntry对象忽略了我刚刚删除了一个这一事实。更重要的是,应用程序崩溃是因为收到的条目(应该删除的条目)没有相关ProductCoreDataEditor仅显示 1 个条目。重新启动应用程序后,购物车再次正确 - 只有 1 个条目,没有我刚刚删除的数据。

尝试 2: 让我们忽略in: context

let removeEntry: (NSManagedObjectContext) -> () = { context in CartEntry.mr_deleteAll(matching: NSPredicate(format: "product.code == %@", product.code)) }

效果2: NO CHANGES IN ** saveWithBlock:completion: ** CONTEXT - NOT SAVING

解决方案

仔细检查您的Delete rules - 问题是 No Action而不是Nullify

最佳答案

MagicalRecord.save 正在将数据保存到 defaultContext

MagicalRecord.save({ (context) in
         _ = data(context)
     }) { (success, error) in
         completion(success,error)
     }

而你的self.localContextmr_root saving??

快速建议:

  1. 使用 MagicalRecord.setupCoreDataStack(withAutoMigrationSqliteStoreNamed: dataStack) 而不是 MagicalRecord.setupCoreDataStack(withStoreNamed: dataStack)。始终让 MagicalRecord 为您处理自动迁移。

  2. 在大多数情况下,我使用 MagicalRecord 的习惯始终坚持使用 defaultContext。对于您的用例,如果您始终使用 MagicalRecord.save 保存数据(它将数据保存到 defaultContext 中),您确实不需要显式创建 self.localContext )。然后你可以简单地使用 let cart: Cart? = Cart.mr_findFirst()随时随地检索您需要的数据。

更新答案

感谢您更新问题@Piotr Gawłowski。

Why there are in: context? Cause when I omit them save is not performing. I've got a warnings like:NO CHANGES IN ** saveWithBlock:completion: ** CONTEXT - NOT SAVING

MagicalRecord.save({(context).. 创建一个新的上下文来执行闭包中的操作,然后它合并回 defaultContext。正如我提到的之前,如果您没有显式指定上下文,MagicalRecord 将回退到 defaultContext。因此,如果您没有添加“inContext:”,则发生的情况是您创建的MagicalRecord.save({(context).. block 内的 defaultContext 中的实体。事实证明,MagicalRecord 的上下文没有发生任何更改。 save({(context).(我的英语很烂,但我知道你很聪明能理解)

并且,您可以使用mr_findFirstOrCreate初始化程序

let addEntry: (NSManagedObjectContext) -> () = { context in
    let entry = CartEntry.mr_findFirstOrCreate(with: NSPredicate(format: "product.code == %@", productCode), in: context) {
        entry.quantity = NSNumber.init(value: (entry.quantity?.intValue)! + 1)
        entry.product = Product.mr_findFirst(with: NSPredicate(format: "code == %@", productCode), in: context)
        entry.code = productCode
        entry.cart = Cart.mr_findFirst(in: context)
}

言归正传,基本上 addfetch 操作都工作正常,对吗?剩下的问题是删除。首先,尝试2就是我上面提到的上下文问题。

所以让我们关注

Effect 1: Completions block returns success = true, error = nil Right after this operations we're refreshing cart with let cart: Cart? = Cart.mr_findFirst() - cart.entries field got 2 CartEntry objects ignoring fact that I just deleted one. What is more app crashes because received entry (one that supposed to be deleted) do not have related Product. CoreDataEditor shows only 1 entry. After restarting applications cart is once again correct - got only 1 entry, without data I just deleted.

  1. 您的delete调用似乎没问题

  2. 应用程序崩溃是您实际上删除了该条目的好兆头

  3. 您重新启动了应用程序,只剩下 1 个条目,证明您的 删除语句完成了它的工作

(您是否使用CoreDataEditor仔细检查结果?)

因此我们可以确认所有其他部分都正常工作,唯一的问题似乎是您没有正确处理数据源更改。您使用的是 UITableView 吗?您是否使用 NSFetchedResultsControllerDelegate 扩展您的类并实现委托(delegate)方法?

请告诉我们该部分的代码。 (用于显示数据的 ViewController)。

关于ios - MagicalRecord - 保存后数据错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42980169/

相关文章:

ios - 从 Swift 函数中的异步调用返回数据

iOS/swift : Add UITapGestureRecognizer to NSMutableAttributedString

ios - iphone nsoperation 应用程序卡住

ios - 从 Swift 中的另一个类刷新 UITableView

ios - 核心数据中的计算属性

iOS NSURLConnection 不从某些 URL 下载文件

ios - 比较和匹配数组值

ios - 检查 Double 中的百分位值

ios - 主从接口(interface)的核心数据实体设计

iphone - CoreData 中的数据建模(具有许多子项的文件夹和文档等)