【问题标题】:Core Data isn't being reset when I close the calling class - how can I reset it?当我关闭调用类时核心数据没有被重置 - 我该如何重置它?
【发布时间】:2021-06-26 20:00:23
【问题描述】:

这个问题在 Stack Overflow 上似乎已经回答了很多次 - 但它仍然不适用于我的用例。核心数据大部分工作正常。关闭文档时出现问题 - 那时我需要重置核心数据,准备好加载下一个文档。实际发生的情况是,下一个要加载的 Document 会加载其所有数据以及所有以前的 Documents 数据 - 并且在应用程序退出并再次重新打开之前它不会重置。

我有一个基于 NSDocument 的应用程序,它可以加载许多不同的文档类型。每种文档类型都在其自己的类中进行描述。例如,Foo 可能是一个非常简单的文档类型,很小,基于文本,处理起来没有问题,因此不需要复杂的类来加载它。另一方面,Bar 是一个巨大的复杂数据库,大小为 GB - 将其全部加载到内存中是没有意义的。

我的 Bar 类使用 Core Data - 它是唯一需要的,因此也是唯一包含此逻辑的。我提到这一点是因为几乎所有关于如何使用 Core Data 的描述都将 Core Data 代码放在 App Delegate 中——这可能是有充分理由的!

在我的栏标题中,我的核心数据设置如下:

@property (nonatomic, strong, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (nonatomic, strong, readonly) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong, readonly) NSDate *readStart;

在我的 Bar .m 中,我有以下内容:

- (NSURL *)dataStoreURL {
    NSString *docDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
    //NSString* filename = [NSString stringWithFormat:@"%@.sql",[StringWangers generateUUIDString]];
    NSString* filename = @"datastore.sql";
    return [NSURL fileURLWithPath:[docDir stringByAppendingPathComponent:filename]];
}

- (NSManagedObjectModel *)managedObjectModel {
    if (_managedObjectModel) {
        return _managedObjectModel;
    }
    _managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
    return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    if (_persistentStoreCoordinator) {
        return _persistentStoreCoordinator;
    }
    
    [NSFileManager.defaultManager removeItemAtURL:self.dataStoreURL error:nil]; // this isn't supposed to be persistent - clear out old crap
    
    NSError *error = nil;
    
    NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption: @(YES), NSInferMappingModelAutomaticallyOption: @(YES)};
    
    _persistentStoreCoordinator = [NSPersistentStoreCoordinator.alloc initWithManagedObjectModel:self.managedObjectModel];
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                   configuration:nil
                                                             URL:self.dataStoreURL
                                                         options:options
                                                           error:&error]) {
        NSLog(@"Unresolved Core Data error with persistentStoreCoordinator: %@, %@", error, [error userInfo]);
    }
    
    return _persistentStoreCoordinator;
}

- (NSManagedObjectContext *)managedObjectContext {
    if (_managedObjectContext) {
        return _managedObjectContext;
    }
    
    if ([self persistentStoreCoordinator]) {
        _managedObjectContext = [NSManagedObjectContext.alloc initWithConcurrencyType:NSMainQueueConcurrencyType];
        [_managedObjectContext setPersistentStoreCoordinator:[self persistentStoreCoordinator]];
    }
    
    return _managedObjectContext;
}

我已经尝试了很多方法来删除这些讨厌的数据 - 包括腰带和牙套,所有东西(我真的不喜欢这样做,因为我想了解发生了什么 - 但我很绝望!) - 这个是“一切”状态……

-(void)deinitialise {
    @try {
        NSLog(@"Deleting old core storage");
        NSArray *allEntities = self.managedObjectModel.entities;
        for (NSEntityDescription *entityDescription in allEntities) {
            NSFetchRequest *fetchRequest = NSFetchRequest.new;
            [fetchRequest setEntity:entityDescription];
            fetchRequest.includesPropertyValues = NO;
            fetchRequest.includesSubentities = NO;

            NSLog(@"%@",fetchRequest);

            NSError *error = nil;
            NSArray *items;
            if (self.managedObjectContext &&
                fetchRequest &&
                ([fetchRequest.sortDescriptors isKindOfClass:NSArray.class] && fetchRequest.sortDescriptors.count > 0) &&
                fetchRequest.predicate) {
                items = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
            }

            if (error) {
                NSLog(@"Error requesting items from Core Data: %@", error.localizedDescription);
            }

            for (NSManagedObject *managedObject in items) {
                [self.managedObjectContext deleteObject:managedObject];
                [self.managedObjectContext save:&error];
                if (error) {
                    NSLog(@"Error deleting items from Core Data: %@", error.localizedDescription);
                }
            }
        }
    }
    @catch (NSException *exception) {
        NSLog(@"Error deleting persistent storage - Exception: %@", exception);
    }
    
    NSError *error = nil;
    NSArray* persistentStoreArray = self.persistentStoreCoordinator.persistentStores;
    for (id store in persistentStoreArray) {
        [self.persistentStoreCoordinator removePersistentStore:store error:&error];
        if (error) {
            NSLog(@"Error Removing Persistent Store: %@", error.localizedDescription);
        }
        NSString* storePath = [store URL].path;
        NSLog(@"%@",storePath);
        [NSFileManager.defaultManager removeItemAtPath:storePath error:&error];
        if (error) {
            NSLog(@"Error Deleting Persistent Store: %@", error.localizedDescription);
        }
    }
    self.persistentStoreCoordinator = nil;
}

有趣的是,- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 仅在我的 Bar 类在文档加载时第一次被调用时被调用,但每次我调用我的 reinitialise 类时。

希望这对某人有意义 - '因为我没有想法。

【问题讨论】:

  • 几乎所有关于如何使用 Core Data 的描述都适用于 iOS,而 NSPersistentDocument 在 iOS 上不可用。 NSPersistentDocument 没有将 Core Data 代码放在 App Delegate 中。创建一个 Xcode 项目,macOS Cocoa 应用,基于文档,Uses Core Data 看看。
  • 您能否澄清一下,当您关闭文档时,您想删除用户 Mac 中的所有数据,而不仅仅是将其从内存中取出?这样就不可能再次加载该数据?我不认为那是你想要的,但既然你像这样使用deleteObject,似乎它可能就是这样。
  • 我现在会满足于将其从内存中删除 - 但你说得对,我真正想要的是完全删除它(这就是我也尝试 removeItemAtPath 的原因)
  • …另外,这是在 Mac 上,而不是在 iOS 上。
  • 在反初始化代码中,您的 if 条件包含 fetchRequest.predicate,但您从未设置谓词:因此 fetchRequest 永远不会执行。关于FileManager的操作,你检查过错误吗?更广泛地说,您可能还需要删除 .sqlite-wal 和 -shm 文件(或使用destroyPersistentStore)。

标签: objective-c cocoa core-data


【解决方案1】:

感谢所有发布建议的人。它们是很好的调查途径——但对于我的特定用例来说,它们都是不正确的。在这种情况下,我所要做的就是:

-(void)deinitialise {
    [self.managedObjectContext reset];
}

我希望这可以帮助遇到此问题的其他人。

【讨论】:

    猜你喜欢
    • 2013-10-21
    • 2023-03-06
    • 1970-01-01
    • 1970-01-01
    • 2023-02-11
    • 2011-07-13
    • 1970-01-01
    • 2016-11-15
    • 1970-01-01
    相关资源
    最近更新 更多