CoreData 自动保存并且自动保存后不加载所有数据

发布于 2025-01-08 09:28:31 字数 3289 浏览 0 评论 0原文

我有一个 NSPersistentDocument 子类,使用 NSManagedObject 子类来存储我的数据。

打开新文档时,我会对数据结构进行一些初始化(少量填充字段)。我注意到,无标题文档会自动保存,当应用程序重新打开时,该文档会被加载。如果应用程序退出,用户不会(默认情况下)收到保存对话框的提示。如果窗口关闭,用户就会关闭。

第一个问题:

我想在用户退出应用程序时调用保存对话框。我不希望这个无标题文档闲逛(在正常情况下)。我要么想保存它,要么想把它扔掉。

我尝试填写:

- (void)applicationWillTerminate:(NSNotification *)aNotification

以便触发要保存的文档。此时在上下文上调用 save: 会出现错误。据我所知,这是因为用户尚未自行保存文件。另外,调用[self close];[[self windowForSheet] close];关闭窗口而不保存。

如何强制出现保存对话框?如何删除无标题文档?

第二个问题(不,我无法数):

由于应用程序启动时,可能有也可能没有要处理的 Untitled 文档,我试图跟踪另一个模型中的状态。我已经发现,当无标题文档出现时,初始数据(我之前提到过)就存在。我的另一个模型有一些元数据,包括填充数据的成功标志/状态。一旦填充的数据全部就位且正确,状态就会如此指示。不幸的是,虽然当应用程序以预先存在的 Untitled 文档启动时正在加载我填充的数据,但元数据类却没有。

请原谅代码的粗糙性,在这一点上,我正在把它搞砸,直到我看到它按照我想要的方式工作,然后再将其抛光:

- (bool) createGameState {
  NSEntityDescription* description = [NSEntityDescription entityForName:[GameState name] inManagedObjectContext:[self managedObjectContext]];
  NSFetchRequest* req = [[NSFetchRequest alloc] init];
  [req setEntity:description];

  NSError *error = nil;
  NSArray *array = [[self managedObjectContext] executeFetchRequest:req error:&error];
  [req release];
  req = nil;

  GameState* result = nil;
  if (array) {
    NSUInteger count = [array count];
    if (!count) {
      // Create the new GameState.
      DebugLog(@"Creating GameState");
      result = [NSEntityDescription insertNewObjectForEntityForName:[GameState name] inManagedObjectContext:[self managedObjectContext]];
      [result setIsLoaded:[NSNumber numberWithBool:NO]];
    } else {
      if (count > 1) {
        NSLog(@"WARNING: Potentially Corrupt Game State. found: %lu", count);
      }
      result = [array objectAtIndex:0];
      if ([result isLoaded]) {
        [self variantLoaded];
      } else {
        // In this case, we have an aborted set-up. Since the game isn't
        // playable, just refuse to create the GameState. This will
        // force the user to create a new game.
        return NO;
      }
    }
  } else {
    DebugLog(@"error: %@", error);
  } 

  [game setState:result];
  return result;
}

请注意,数组始终存在,并且计数始终为零。不,我没有在任何地方显式调用 save: 。我依赖于标准自动保存,或者用户执行保存。

编辑:

我安装了核心数据编辑器应用程序。事实证明,问题不在于保存数据,而在于加载数据。 (注意:由于另一个问题,当指示保存为 XML 时,应用程序会保存为二进制文件,这会导致很多麻烦。)

我已将其分解为最简单的代码,该代码应该拾取数组中 GameState 类型的所有对象。它检索不到任何内容,尽管保存的文件中显然存在适当类型的对象:

  NSManagedObjectContext* moc = [self managedObjectContext];
  NSEntityDescription* entity = [NSEntityDescription entityForName:@"GameState" inManagedObjectContext:moc];

  NSFetchRequest* req = [[NSFetchRequest alloc] init];
  [req setEntity:entity];


  NSError *error = nil;
  NSArray *array = [moc executeFetchRequest:req error:&error];

数组不为空,但 [array count] 为 0。

在这一点上,我猜这很简单我俯视着

第二次编辑:

我添加了 -com.apple.CoreData.SQLDebug 5 并保存为 SQLite。对 executeFetchRequest 的调用不会生成任何调试日志。我确实看到日志中显示了 INSERT INTO ZGAMESTATE 条目。似乎 executeFetchRequest 没有传递到后端。

第三次编辑(这个会被烧毁):

我使用核心数据创建了一个新的 xcode 项目(就像我对另一个项目所做的那样)。我只复制了这个函数(在必要时进行存根)并在 windowControllerDidLoadNib 中调用了它。在这个新项目中,上面的代码可以工作。

I have an NSPersistentDocument subclass using NSManagedObject subclasses for my data.

When a new document is opened, I do some initializing of data structures (trivial amount of populating fields). What I've noticed is that the Untitled document gets autosaved, and when the application re-opens, that document gets loaded. If the application quits, the user doesn't (by default) get prompted with the save dialog. If the window closes, the user does.

First question:

I want to call up the save dialog when the user quits the application. I don't want this Untitled document hanging around (under normal circumstances). I either want it saved or trashed.

I attempted to fill out:

- (void)applicationWillTerminate:(NSNotification *)aNotification

In order to trigger the document to be saved. Calling save: on the context at this point gives an error. From what I can tell, this is because the user hasn't yet saved the file on their own. In addition, calling [self close]; or [[self windowForSheet] close]; close the window without saving.

How can I force the save dialog to come up? How can I trash the untitled document?

Second question (no, I can't count):

Since when the application starts, there may or may not be an Untitled document to deal with, I'm trying to keep track of the state in another model. I've already found that the initial data (to which I referred earlier) is present when the Untitled document came up. My other model has some metadata, including a success flag/state for the populated data. Once the populated data is all in place and correct, the state indicates as such. Unfortunately, while my populated data is being loaded when the app starts with a pre-existing Untitled document, the metadata class is not.

Please excuse the roughness of the code, at this point, I'm mucking it up until I can see that it's working how I want before I polish it back off:

- (bool) createGameState {
  NSEntityDescription* description = [NSEntityDescription entityForName:[GameState name] inManagedObjectContext:[self managedObjectContext]];
  NSFetchRequest* req = [[NSFetchRequest alloc] init];
  [req setEntity:description];

  NSError *error = nil;
  NSArray *array = [[self managedObjectContext] executeFetchRequest:req error:&error];
  [req release];
  req = nil;

  GameState* result = nil;
  if (array) {
    NSUInteger count = [array count];
    if (!count) {
      // Create the new GameState.
      DebugLog(@"Creating GameState");
      result = [NSEntityDescription insertNewObjectForEntityForName:[GameState name] inManagedObjectContext:[self managedObjectContext]];
      [result setIsLoaded:[NSNumber numberWithBool:NO]];
    } else {
      if (count > 1) {
        NSLog(@"WARNING: Potentially Corrupt Game State. found: %lu", count);
      }
      result = [array objectAtIndex:0];
      if ([result isLoaded]) {
        [self variantLoaded];
      } else {
        // In this case, we have an aborted set-up. Since the game isn't
        // playable, just refuse to create the GameState. This will
        // force the user to create a new game.
        return NO;
      }
    }
  } else {
    DebugLog(@"error: %@", error);
  } 

  [game setState:result];
  return result;
}

Note that array is always present, and count is always zero. No, I'm not explicitly calling save: anywhere. I'm relying on the standard auto-save, or the user performing a save.

EDIT:

I installed the Core Data Editor app. It turns out the issue isn't on saving the data, but on loading it. (Note: Due to another issue, the app saves as binary when instructed to save as XML, which causes much head banging.)

I've broken it down to the simplest code, which should pick up all objects of type GameState in an array. It retrieves none, despite there clearly being objects of the appropriate type in the saved file:

  NSManagedObjectContext* moc = [self managedObjectContext];
  NSEntityDescription* entity = [NSEntityDescription entityForName:@"GameState" inManagedObjectContext:moc];

  NSFetchRequest* req = [[NSFetchRequest alloc] init];
  [req setEntity:entity];


  NSError *error = nil;
  NSArray *array = [moc executeFetchRequest:req error:&error];

Array is not null, but [array count] is 0.

At this point, I'm guessing it's something simple that I'm overlooking.

Second EDIT:

I added -com.apple.CoreData.SQLDebug 5 and saved as SQLite. The call to executeFetchRequest does not generate any debug logs. I do see the INSERT INTO ZGAMESTATE entry show up in the logs. It seems that executeFetchRequest is not getting passed to the backend.

Third EDIT (this one burns):

I created a new xcode project, using core data (as I had with the other). I copied just this one function (stubbing where necessary) and plopped a call to it in windowControllerDidLoadNib. In this new project, the code above works.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

铁憨憨 2025-01-15 09:28:31

发现问题了。

我错误地在 Document- (id) init 调用中加载对象。移至windowControllerDidLoadNib(这是我在测试版本中所做的)并且工作正常。

Found the problem.

I errantly was loading objects in Document's - (id) init call. Moved to windowControllerDidLoadNib (which is what I did in the test version) and it worked fine.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文