立即启用保存文档 NSManagedObjectContext 吗?

2023-12-29

从 10.7 上带有 CoreData 模板的标准 Xcode 基于文档的应用程序开始,我遇到了一些令人沮丧的行为。我确信这是我忽略的简单事情。

假设在我的 NSPersistentDocument 子类中,我有这样的东西,连接到窗口中的一个按钮:

- (IBAction)doStuff:(id)sender
{        
    NSEntityDescription* ent = [[self.managedObjectModel entitiesByName] valueForKey: @"MyEntity"];
    NSManagedObject* foo = [[[NSManagedObject alloc] initWithEntity: ent insertIntoManagedObjectContext: self.managedObjectContext] autorelease];
    [self.managedObjectContext save: NULL];
}

如果我创建一个新文档并单击该按钮,我将收到以下错误:This NSPersistentStoreCoordinator has no persistent stores. It cannot perform a save operation.我明白了。我们还没有保存,没有持久存储。说得通。

现在假设我将其分为两个操作,连接到不同的按钮,如下所示:

- (IBAction)doStuff:(id)sender
{        
    NSEntityDescription* ent = [[self.managedObjectModel entitiesByName] valueForKey: @"MyEntity"];
    NSManagedObject* foo = [[[NSManagedObject alloc] initWithEntity: ent insertIntoManagedObjectContext: self.managedObjectContext] autorelease];
}

- (IBAction)doOtherStuff:(id)sender
{        
    [self.managedObjectContext save: NULL];
}

如果我创建一个新文档并按第一个按钮,那么在按该按钮后的某个不确定时间(弄脏文档),自动保存将出现并自动保存文档,这将在临时位置创建一个存储。如果我按下第二个按钮,就不会出现任何投诉(因为现在有一家商店。)

我需要我的文档能够从一开始就进行 ManagedObjectContext 保存。我正在后台线程上启动一些内容,并且我需要后台上下文的保存操作(和通知),以便将后台线程所做的更改合并到主线程的 ManagedObjectContext 中。

我想过尝试强制自动保存,但自动保存过程似乎完全异步,因此我必须跳过所有可能导致 ManagedObjectContext 保存的 UI 交互,直到第一个自动保存操作完成。

我还考虑过创建一个内存存储来弥合创建新文档和第一个自动保存之间的差距,但是我不清楚如何将内存存储中的内容迁移到磁盘存储并与第一次自动保存操作。

有人对我如何处理这个问题有任何想法吗?


所以我对此闲逛了一段时间,包括尝试@Aderstedt 的建议。这种方法不起作用,因为伪造通知似乎只是告诉接收上下文“嘿,检查持久性存储,我已经更新了它们!”,而实际上,我没有,因为没有。我最终找到了一种有效的方法。不幸的是,它仅依赖于 Lion 的功能,因此我仍在寻找一种不需要 Lion 的方法来实现此目的。

背景

我想使用 NSPersistentDocument 方法。虽然我没有在任何地方找到明确的记录,但我发现了几个论坛帖子,并经历了一堆你不能称之为的经验证据-[NSManagedObjectContext save:]在属于 NSPersistentDocument 的上下文上。正如问题中提到的,如果您在保存文档之前调用它,它将具有no存储,因此保存将失败。即使在存储存在之后,通过直接保存上下文(而不是通过文档保存 API),您可以有效地更改 NSPersistentDocument 后面的磁盘上表示形式,并且您将获得文档弹出表,其中显示:

文件已被另一个应用程序修改

简而言之,NSPersistentDocument 期望控制关联的 NSManagedObjectContext 本身的保存操作。

另外值得一提的是:这里的目标是确保 UI 使用的上下文不会触发(或至少触发最少的)I/O 以保持响应。我最终确定的模式是拥有 3 个上下文。 NSPersistentDocument 拥有的一种上下文,负责与文档一起执行文件 I/O。用于将 UI 绑定到的第二个有效只读上下文。 (我意识到很多人想要改变模型的 UI,所以这对他们来说可能不那么令人兴奋,但这对我来说不是必需的。)第三个上下文用于从 Web 异步加载数据的后台线程服务,并希望将其推送到其他上下文中,以便它可以保存在磁盘上并呈现在 UI 中,而不会潜在地阻塞网络 I/O 上的 UI。

Lion专用解决方案

Lion 的 CoreData 实现中新的父/子 NSManagedObjectContext 功能是perfect为了这。我用并发类型 NSPrivateQueueConcurrencyType 的新 MOC 替换了 NSPersistentDocument 的 NSManagedObjectContext。这将是“根”上下文。然后我使用 NSMainQueueConcurrencyType 并发创建了 UI 上下文,并使其成为根上下文的子上下文。最后,我将网络加载上下文设置为 NSPrivateQueueConcurrencyType 上下文,它是 UI 上下文的子级。其工作原理是我们在后台启动网络加载操作,它更新网络上下文。完成后,它会保存上下文。对于父/子关系,保存子上下文会将更改推送到父上下文(UI 上下文),但不会not将父上下文保存到存储中。就我而言,我还监听来自网络上下文的 NSManagedObjectContextDidSaveNotification 通知,然后告诉它的父级也进行保存(这会将 UI 上下文中的更改推送到根/磁盘上下文,但不会将其保存到磁盘。)

在这一系列事件的最后,所有上下文都是一致的,并且我们仍然没有强制真正保存底层根上下文,因此我们没有与 NSPersistentDocument 管理磁盘的角色发生冲突。表示。

一个问题是,如果您想防止子上下文的保存生成撤消(即,这是一个网络加载操作,没有什么可撤消的),您必须在将更改传播到链上时在每个父上下文上禁用UndoRegistration。

狮友前的努力

我真的很想找到一个与 Lion 之前兼容的解决方案来解决这个问题。在放弃之前我尝试了一些事情。我首先尝试在文档初始化时将内存存储与 PSC 关联起来,这样我就可以在保存文档之前进行 NSManagedObjectContext 保存,然后在第一次保存时迁移内存存储。那部分效果很好。但是一旦存在磁盘存储,这种方法就是假的,因为在将其保存到磁盘后,我们会遇到同样的问题,即任何连接到 NSPersistentDocument 拥有的 PSC 的 MOC 的保存都必须由文档完成。

我还尝试破解一种机制,使用 NSManagedObjectContextObjectsDidChangeNotification 有效负载将更改从一个上下文移动到另一个上下文。尽管我能够让它发挥作用(对于“工作”的一些名义定义),但我看到这种方法即将出现的大问题。具体来说,迁移这些更改很容易once但如果在保存操作之前它再次发生变化怎么办?然后,我将不得不维护源上下文中的 OID 到目标上下文中的 OID 的长期映射。这很快就变得丑陋了。如果有人感兴趣,这就是我想出的:

@interface NSManagedObjectContext (MergeChangesFromObjectsDidChangeNotification)
- (void)mergeChangesFromObjectsDidChangeNotification: (NSNotification*)notification;
@end

@implementation NSManagedObjectContext (MergeChangesFromObjectsDidChangeNotification)

- (void)mergeChangesFromObjectsDidChangeNotification: (NSNotification*)notification
{
    if (![NSManagedObjectContextObjectsDidChangeNotification isEqual: notification.name])
        return;

    if (notification.object == self)
        return;

    NSManagedObjectContext* sourceContext = (NSManagedObjectContext*)notification.object;

    NSAssert(self.persistentStoreCoordinator == sourceContext.persistentStoreCoordinator, @"Can't merge changes between MOCs with different persistent store coordinators.");

    [sourceContext lock];

    // Create object in the local context to correspond to inserted objects...
    NSMutableDictionary* foreignOIDsToLocalOIDs = [NSMutableDictionary dictionary];
    for (NSManagedObject* foreignMO in [[notification userInfo] objectForKey: NSInsertedObjectsKey])
    {
        NSManagedObjectID* foreignOID = foreignMO.objectID;
        NSManagedObject* localMO = [[[NSManagedObject alloc] initWithEntity: foreignMO.entity insertIntoManagedObjectContext: self] autorelease];
        [foreignOIDsToLocalOIDs setObject: localMO.objectID forKey: foreignOID];
    }

    // Bring over all the attributes and relationships...
    NSMutableSet* insertedOrUpdated = [NSMutableSet set];
    [insertedOrUpdated unionSet: [[notification userInfo] objectForKey: NSInsertedObjectsKey]];
    [insertedOrUpdated unionSet: [[notification userInfo] objectForKey: NSUpdatedObjectsKey]];

    for (NSManagedObject* foreignMO in insertedOrUpdated)
    {
        NSManagedObjectID* foreignOID = foreignMO.objectID;
        NSManagedObjectID* localOID = [foreignOIDsToLocalOIDs objectForKey: foreignOID];
        localOID = localOID ? localOID : foreignOID;
        NSManagedObject* localMO = [self objectWithID: localOID];

        // Do the attributes.
        [localMO setValuesForKeysWithDictionary: [foreignMO dictionaryWithValuesForKeys: [[foreignMO.entity attributesByName] allKeys]]];

        // Do the relationships.
        NSDictionary* rByName = foreignMO.entity.relationshipsByName;
        for (NSString* key in [rByName allKeys])
        {
            NSRelationshipDescription* desc = [rByName objectForKey: key];
            if (!desc.isToMany)
            {
                NSManagedObject* relatedForeignMO = [foreignMO valueForKey: key];
                NSManagedObjectID* relatedForeignOID = relatedForeignMO.objectID;
                NSManagedObjectID* relatedLocalOID = [foreignOIDsToLocalOIDs objectForKey: relatedForeignOID];
                relatedLocalOID = relatedLocalOID ? relatedLocalOID : relatedForeignOID;
                NSManagedObject* localRelatedMO = [self objectWithID: relatedLocalOID];
                [localMO setValue: localRelatedMO forKey: key];
            }
            else
            {
                id collection = [foreignMO valueForKey: key];
                id newCollection = [NSMutableSet set];
                if ([collection isKindOfClass: [NSOrderedSet class]])
                {
                    newCollection = [NSOrderedSet orderedSet];
                }

                for (NSManagedObject* relatedForeignMO in collection)
                {
                    NSManagedObjectID* relatedForeignOID = relatedForeignMO.objectID;
                    NSManagedObjectID* relatedLocalOID = [foreignOIDsToLocalOIDs objectForKey: relatedForeignOID];
                    relatedLocalOID = relatedLocalOID ? relatedLocalOID : relatedForeignOID;
                    NSManagedObject* localRelatedMO = [self objectWithID: relatedLocalOID];
                    [newCollection addObject: localRelatedMO];
                }
                [localMO setValue: newCollection forKey: key];
            }
        }
    }

    // And delete any objects which pre-existed in my context.
    for (NSManagedObject* foreignMO in [[notification userInfo] objectForKey: NSDeletedObjectsKey])
    {
        NSManagedObjectID* foreignOID = foreignMO.objectID;
        NSManagedObject* localMO = [self existingObjectWithID: foreignOID error: NULL];
        if (localMO)
        {
            [self deleteObject: localMO];
        }
    }

    [sourceContext unlock];
}

@end

结论

在并发管理的改进和父/子功能之间,我很快就失去了追求 pre-Lion 解决方案的兴趣。我开始认为,Lion 之前的解决方案实际上是“不要使用 NSPersistentDocument”。据我所知,如果我放弃这个要求,所有这些痛点都会消失。如果没有它,您可以随时保存上下文并迁移存储,但自然地您必须自己完成所有工作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

立即启用保存文档 NSManagedObjectContext 吗? 的相关文章

  • UITableView 未更新

    我正在使用核心数据模型和 UITableViewController 表视图 我的模型似乎工作得很好 但是当我向模型添加实体时 我的表视图没有更新 我相信我的模型有效的原因是 当我添加一个实体时 在运行时视图中不会显示任何内容 但是如果我剪
  • iOS 的云存储选项

    我正在尝试创建一个后端 让许多用户可以在我正在创建的 iPhone 应用程序中相互通信 我尝试过使用 Core Data Google App Engine Google Cloud Storage 和 Amazon Web Service
  • 使用Core Data中的Cascade删除关系对象

    我希望使用核心数据执行一些简单的删除 但仅需要对此的一些建议 我有一个包含交易 名称 事件和日期实体的模型 该交易与其他每个实体都有链接 在应用程序中 当用户将信息添加到文本字段时 该信息会保存到 4 个选项卡的表格视图控制器中 第一个选项
  • CoreData 多对多添加错误

    不确定我在这里做错了什么 School has a to many to Student and Student has its inverse 一点测试代码如下 class Student interface School NSManag
  • 如何使用 Core Data (iPhone) 存储 CLLocation?

    我试图保存一个位置 然后使用 Core Location MapKit 和 Core Data 框架在地图上检索该位置 我所做的只是创建了名为 POI 的实体 并添加了诸如纬度 双精度类型 经度 双精度类型 等属性以及其他一些属性 简而言之
  • 轻量级核心数据迁移后,如何为现有实体的新属性设置默认值?

    我已经成功完成了核心数据模型的轻量级迁移 我的自定义实体 Vehicle 收到了一个新属性 tirePressure 它是 double 类型的可选属性 默认值为 0 00 当从商店中获取 旧 车辆 在迁移发生之前创建的车辆 时 其 tir
  • 如何让NSManagedObject不出错?

    我目前正在调试另一个开发人员编写的一个大项目 该项目使用CoreData我对此很陌生 我遇到了崩溃 这是由于某些NSManagedObject是一个错误 我对什么是错误不太了解 我想将对象转换为 非错误 看看它是否有帮助 阅读文档让我想到t
  • 更改 NSManagedObject 属性而不触发委托方法?

    有什么方法 或技巧 可以修改NSManagedObject目前由一名代表持有NSFetchedResultsController不触发didChangeObject and controllerWillChangeContent 委托方法
  • 保存时出现 iphone 核心数据未解决的错误

    尝试保存时 我从核心数据中收到一条奇怪的错误消息 但问题是错误不可重现 在执行不同任务时 它会在不同时间出现 错误消息 Unresolved error Domain NSCocoaErrorDomain Code 1560 UserInf
  • NSUndoManager 会撤消后台发生的更改吗?

    我有一个编辑视图控制器 我正在使用 NSUndoManager 它是我的持久性存储 核心数据项目 的一组 我的应用程序的功能之一是与外部服务器同步 我想知道的是 如果我正在视图中编辑某些内容 同时应用程序正在与服务器同步 如果我改变主意并决
  • 主队列上的dispatch_sync 与dispatch_async

    请耐心等待 这需要一些解释 我有一个类似于下面的函数 上下文 aProject 是一个名为 LPProject 的核心数据实体 其数组名为 memberFiles 其中包含另一个名为 LPFile 的核心数据实体的实例 每个 LPFile
  • Xcode 4 Core Data:如何使用在数据模型编辑器中创建的获取属性

    如何在 Xcode 4 中实现获取的属性 Here is an example of two entities a book and a page 我按照此处的指南创建了一个获取的属性 该属性使用变量 FETCH SOURCE 引用来自源实
  • 核心数据:为什么必须调用重新加载数据才能使我的应用程序运行?

    我花了整个晚上调试一个简单的应用程序 该应用程序从网络检索一张图像 是的 是的 旨在让我的生活更轻松 并将其显示在表格视图中 我这样做是为了练习学习核心数据 在我修复它之前 错误消息显示如下 2012 09 30 06 16 12 854
  • 在视图之间传递核心数据实体变量

    我无法理解如何在视图之间使用核心数据实体变量 为了更好地理解我的问题是什么 我的代码如下 View A 基本上 您必须将完整预算实体或相关预算实体的 ID 从视图 A 传递到视图 B 由于不知道您的应用程序的视图层次结构和逻辑 我假设您选择
  • NSManagedObject 的 Xcode 9 构建问题:Date 与 NSDate

    Xcode 9 生成不同的代码Date模拟器与设备中实体的类型属性 我有codegen功能下Class set to category extension在核心数据中 直到 Xcode 8 3 最新 一切都工作正常 NSDate总是 下面是
  • 现有的和未输入错误的密钥的 NSUnknownKeyException

    我得到以下输出 Terminating app due to uncaught exception NSUnknownKeyException reason
  • 核心数据迁移失败,并显示“找不到源存储的模型”,但存在源的 ManagedObjectModel

    我有一个使用 core data 的可可应用程序 它现在是其托管对象模型的第四个版本 我的托管对象模型包含抽象实体 但到目前为止 我已成功通过创建适当的映射模型并使用 addPersistentStoreWithType configura
  • 编译托管对象模型时有什么方法可以忽略丢失的反向警告吗?

    标题几乎包含了问题 我们发布了一个应用程序 其数据模型的逆配置不正确 我们在下一个版本中使用新版本的数据模型修复了这些问题 但 Xcode 在编译以前的数据模型版本时仍然显示警告 我不想破坏将文档从旧数据模型迁移到新数据模型的能力 并且我非
  • 是否可以在“NSFetchRequest”中按子类排序而不添加其他属性?

    我想对结果进行分组NSFetchRequest按实体 这些实体都共享相同的抽象父级 例如 animal cat dog The NSFetchRequest has includesSubentities set TRUE and enti
  • iOS 7 NS 单线程安全合并冲突

    重新排序两行后 在单线程应用程序上保存简单的数据时遇到问题 我已经成功地简化了编码以重现错误 并且希望其他人尝试这一点时得到第二个意见 这是一次健全性检查 因为我怀疑 iOS 7 引入的核心数据问题 而这在 iOS 6 中工作正常 首先 启

随机推荐

  • mongoose 更新数组或添加到数组

    我已经尝试让它运行一段时间了 但我不知道我做错了什么 我有两个这样的模式 const paymentSchema new Schema year month type String required true status type Boo
  • 为什么SmartGWT没有分页网格?

    很想知道为什么SmartGWT没有分页网格 它是所有企业应用程序必须具备的功能 我找到了 Serendipity 示例 但它在最新版本中不起作用SmartGWT 我可以期待未来支持分页的网格吗 目前 SmartGWT 不支持分页网格 但有多
  • 如何在Flutter中使用TextFormField的按键事件?

    有什么办法可以捕获文本字段中的按键吗 就我而言 当用户在文本字段内按回车键时 这些值将被存储 为此 我需要像 Kotlin Android 中那样使用 Keypress event 我这周才开始尝试 flutter 因为它很有趣而且是跨平台
  • 在c中的Linux套接字编程中从侦听和接受的连接中提取IP

    在下面的代码中 我想在接受传入连接后提取已连接客户端的 IP 地址 之后我应该做什么accept 实现它吗 int sockfd newsockfd portno clilen portno 8090 clilen 0 pthread t
  • 使用 UrlHelper.Action 方法生成 url 时出现空引用异常

    由于某种原因 当某些机器人访问该网站时 会生成一个带有UrlHelper Action方法引发空异常System Web HttpServerVarsCollection Get 我已经做了一些调试 调用堆栈开始尝试从以下位置获取 HTTP
  • 无法使用 android 4.4 旋转模拟器[重复]

    这个问题在这里已经有答案了 我已经将我的sdk更新到最新版本 android 4 4 并启动了模拟器 但现在似乎无法使用CTRL F11旋转屏幕 屏幕发生变化但所有应用程序都没有改变 我不知道这是否是一个相关问题 但我可以看到 即使我创建了
  • 可编辑的组合框,绑定到不在列表中的值

    我有可编辑的组合框 其中首选项目并不总是位于下拉列表中 我希望能够在文本框中手动输入文本 该文本将传播到绑定到 SelectedValue 的字符串 现在 仅当输入的值位于 ComboBox 项中的值中时 绑定到 SelectedValue
  • NameError:名称“N_TOKENS”未定义

    我是 Python 新手 刚刚开始安装 Windows 版 PyCharm 从 Skype 下载了一些示例代码来测试他们的 SkypeKit API 但是 一旦我按下调试按钮 我就会得到 我安装了 Python 2 7 和 Django 1
  • 从 Chrome 开发工具扩展检查 WebSockets 帧

    我想创建一个 Chrome 开发者工具扩展 一个新面板 来分析我们自己网站上的 WebSockets 框架 据我所理解 http developer chrome com extensions devtools network html h
  • SQL Server 中具有多列的“In”子句

    我有一个根据提供的键从数据库检索数据的组件 不过 我希望我的 java 应用程序能够获取单个数据库命中中所有键的所有数据 以加快速度 当我只有一把钥匙时 我可以使用 in 子句 在处理多个键时 我可以在 oracle 中使用以下查询 SEL
  • 如何显示数组中与另一个数组的值相关的值,javascript

    我试图让该名称与与该名称相关的分数一起显示 因此 如果最高分是 98 我希望 Joels 的名字出现在显示屏上 此处显示名字 var names Ben Joel Judy Anne var scores 88 98 77 88 var a
  • 获取日期期间最畅销的 10 种产品

    我想返回用户指定日期内销量最高的 10 种产品 数量最多 我的数据库表 Orders OrderId OrderDate 订单 产品 ProductID OrderID Quantity Products ProductID Product
  • 多线程 Java 应用程序的性能

    我想了解多线程环境中的性能 为此 我编写了一个小测试 在我的机器 四核 Intel Windows XP Sun JDK 1 6 0 20 上运行 结果令人惊讶 该测试基本上是一个线程安全计数器 使用以下任一方法进行同步synchroniz
  • 是否可以安排在特定日期和时间发布?

    我正在使用 Azure DevOps 发布管道来自动化部署 我想安排发布创建在特定的日期和时间进行 但根据下面的屏幕截图 只能选择一周中的几天 并且您不能将触发器指定为仅一次 这是一个问题 因为触发器将导致每周在指定的日期进行发布 并且我们
  • @synchronized vs. NSLock 实例 vs. pthread_mutex_t

    我正在观看一个关于多线程的 2 年前的 教程视频 其中指出 NSLock实例比使用快 3 倍 同步 pthread mutex t比 2 倍快NSLock实例 实际上比 同步 这是真的 我还没有找到任何权威的说法 但我只是想在 StackO
  • 将石墨指标偏移当前时间范围内的最低值

    我有带有 Graphite 指标的 Grafana 我有一个图表显示EnqueueCountActiveMQ 中的某些特定队列 问题是EnqueueCount显示自创建队列以来的所有值 因此当我将 Grafana 中的时间范围缩小到 今天到
  • 向 ggplot 图形添加文件名或其他注释

    我使用 ggplot 来制作大部分图形 这些可以是单面板 也可以是多面的 为了更容易跟踪修订 我想在绘图的角落生成一个包含一些文本的小标签 在伪代码中 我正在寻找这样的东西 generate the initial plot p lt gg
  • WPF/MVVM 在运行时加载用户控件

    我知道有很多关于我的问题的文章 但我找不到解决方案 我是 WPF MVVM 的新手 我尝试了解 MVVM 逻辑 所以我做了一个小项目来理解这一点 对于我以后的应用程序 我想将用户控件动态加载到我的窗口中 在我的 StartView 中 我有
  • UI 的可排序列表的动画过渡

    我正在与一个jQueryUI可排序列表 并且想要在以下情况下为过渡设置动画li当我向上或向下拖动元素时 s 会四处移动 作为Apple已经在他们的iPod app重新排列播放列表的歌曲时 这可能吗 我已经搜索了几个小时 但找不到任何有用的东
  • 立即启用保存文档 NSManagedObjectContext 吗?

    从 10 7 上带有 CoreData 模板的标准 Xcode 基于文档的应用程序开始 我遇到了一些令人沮丧的行为 我确信这是我忽略的简单事情 假设在我的 NSPersistentDocument 子类中 我有这样的东西 连接到窗口中的一个