在 Core Data 中从 AppDelegate 执行回滚功能时需要访问 ManagedObjectContext 的同一实例

Posted

技术标签:

【中文标题】在 Core Data 中从 AppDelegate 执行回滚功能时需要访问 ManagedObjectContext 的同一实例【英文标题】:Need access to same instance of ManagedObjectContext when performing rollback functionality from AppDelegate in Core Data 【发布时间】:2015-02-12 19:43:43 【问题描述】:

在我的 ios 应用程序中,我使用 Core Data 来获取和删除一个非常大的数据集。此过程大约需要 5-10 秒。我想做的是执行回滚,以防用户决定在该过程完成之前关闭设备。但是,问题是让 NSManagedObjectContext 的 SAME 实例从适当的 AppDelegate 方法调用回滚函数。在我的应用程序中,我使用这样的 Singleton 对象调用我的核心数据方法:

static MySingleton *sharedSingleton = nil;


+ (MySingleton *) sharedInstance 

    if (sharedSingleton == nil) 
        sharedSingleton = [[super alloc] init];
    
    return sharedSingleton;

在我的应用程序中,我返回一个 NSManagedObjectContext 的实例,如下所示:

- (NSManagedObjectContext *) managedObjectContext

    if (_managedObjectContext != nil) 
        return _managedObjectContext;
    
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];

    if (coordinator != nil) 

        _managedObjectContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSMainQueueConcurrencyType];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];

        //Undo Support
        NSUndoManager *anUndoManager = [[NSUndoManager alloc] init];
        [self.managedObjectContext setUndoManager:anUndoManager];
    
    return _managedObjectContext;

然后我调用它,并将它分配给这样的引用:

NSManagedObjectContext *context = [[MySingleton sharedInstance] managedObjectContext];

如何使这个 ManagedObjectContext 实例可供我在 AppDelegate 中使用,以便我可以调用回滚函数?

【问题讨论】:

【参考方案1】:

首先,创建单例的更好(更安全)方法如下所示:Create singleton using GCD's dispatch_once in Objective C,即:

+ (instancetype)sharedInstance

    static dispatch_once_t once;
    static id sharedInstance;
    dispatch_once(&once, ^
        sharedInstance = [[self alloc] init];
    );
    return sharedInstance;

接下来,由于您创建了一个必须停留几秒钟的托管对象上下文,因此您必须在某处对其进行强引用。

如果您正在调试并且对代码的一些基本假设提出质疑,请为托管对象上下文命名(或记录 MOC 指针的内存地址),以便稍后在调试器中进行检查,亲自验证一下,您确实在处理同一个问题。

还请注意,如果您仅为此类导入创建了专用的托管对象上下文,则无需回滚它。你可以直接丢弃它。

在我的应用程序中,我通常有一个父(根)托管对象上下文和几个子上下文;一个子用于主线程,另一个子用于导入类型操作。

【讨论】:

【参考方案2】:

作为替代解决方案,您可以创建一个多上下文场景,而不是回滚更改,在该场景中,子托管对象上下文添加您需要的所有数据,最终完成后,您保存将新数据发送到的子上下文主要管理对象。这样,在整个过程完成之前,主托管对象上下文不会受到影响。

这是一篇很棒的文章作为参考Multi-Context CoreData。

基本上你需要做的是

// create main MOC
_mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_mainContext setPersistentStoreCoordinator:_persistentStoreCoordinator];

// create child MOC
_childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
_childContext.parentContext = _mainContext;

希望对您有所帮助。

【讨论】:

以上是关于在 Core Data 中从 AppDelegate 执行回滚功能时需要访问 ManagedObjectContext 的同一实例的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift Core Data 中从一对多关系中获取对象

如何在 Swift 中从 Core Data 中删除数据时删除 UITableView 行?

在 Core Data 中从 AppDelegate 执行回滚功能时需要访问 ManagedObjectContext 的同一实例

如何在 Swift 中从 Core Data 访问子数据和父数据

Singleton 类 DataLoader - 在 AppDelegate 中从 Core Data 设置值,但无法访问其他类中的 DataLoader 变量

在 SwiftUI 中将 @FetchRequest 与 Core Data 一起使用时修改 nil 排序行为