2

NSDocument は、引き続きソフトウェア メンテナンスの悪夢です。

特定のブロッキングダイアログを同期的に処理したいという問題を抱えている人はいますか?

BEGIN EDIT:同期的に待機できるソリューションを見つけたかもしれません

これが「Apple 承認済み」のソリューションであることを確認できる人はいますか?

static BOOL sWaitingForDidSaveModally = NO;
BOOL gWaitingForDidSaveCallback = NO; // NSDocument dialog calls didSave: when done



...
  gWaitingForDidSaveCallback = true;
  [toDocument saveDocumentWithDelegate:self 
                       didSaveSelector:@selector(document:didSave:contextInfo:)  
                           contextInfo:nil];
   if ( gWaitingForDidSaveCallback )
   {
      // first, dispatch any other potential alerts synchronously
      while ( gWaitingForDidSaveCallback && [NSApp modalWindow] )
         [NSApp runModalForWindow: [NSApp modalWindow]];

      if ( gWaitingForDidSaveCallback )
      {
         sWaitingForDidSaveModally = YES;
         [NSApp runModalForWindow: [NSApp mbWindow]]; // mbWindow is our big (singleton) window
         sWaitingForDidSaveModally = NO;
      }
   }
...


- (void)document:(NSDocument *)doc didSave:(BOOL)didSave contextInfo:(void  *)contextInfo
{
   [self recordLastSaveURL];
   gWaitingForDidSaveCallback = NO;
   if ( sWaitingForDidSaveModally )
      [NSApp stopModal];

}

編集終了

Snow Leopard/Lion/ML をサポートする必要があります

アプリの終了は醜いプロセスです。ユーザーが終了することを決定し、ドキュメントに保存が必要な変更がある場合、私はこれを呼び出します:

  gWaitingForDidSaveCallback = true;
  [toDocument saveDocumentWithDelegate:self 
                       didSaveSelector:@selector(document:didSave:contextInfo:)  
                           contextInfo:nil];

は本当にこの呼び出しを同期させたいと思っていますが、最新の Lion では、これによりアプリがハングします。

   while ( gWaitingForDidSaveCallback )
   {
      // didSave: callback clears sWaitingForDidSaveCallback
      // do my own synchronous wait for now
      [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceReferenceDate:0.05]];
   }

ハングの私の最善の推測は、ウィンドウを閉じるボタンの mouseDown: が NSDocument を混乱させていることです。

そのため、ユーザーがさまざまな危険なホットキーを実行できないように、アプリのメイン ループに保守不可能なステート マシン ロジックを追加する必要があります。

よし、ニヤニヤして我慢すると、また障害物にぶつかる!

以前の OS バージョン/SDK では、[NSApp modalWindow] は、この状態にあるときにウィンドウを返します。今はそうではありません!うーん...
NSDocument には、この状態にあるときにテストする API がありません!

そのため、この状態をグローバルにチェックするメカニズムはありません! ステート マシンにさらに別のステート変数を追加する必要があります。

すべての OS バージョンと現在 (および将来) のすべての SDK で機能する、この問題に対するよりクリーンなソリューションを持っている人はいますか?

4

2 に答える 2

2

より良い方法は、保存されていないドキュメントをチェーンで保存することです。これはとても簡単だ:

// Catch application terminate event
-(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
  NSDocumentController *dc = [NSDocumentController sharedDocumentController];
  for (NSInteger i = 0; i < [[dc documents] count]; i++)
  {
    Document *doc = [[dc documents] objectAtIndex:i];
    if ([doc isDocumentEdited])
    {
      // Save first unsaved document
      [doc saveDocumentWithDelegate:self
                    didSaveSelector:@selector(document:didSave:contextInfo:)
                        contextInfo:(__bridge void *)([NSNumber numberWithInteger:i + 1])]; // Next document
      return NSTerminateLater;  // Wait until last document in chain will be saved
    }
  }
  return NSTerminateNow;  // All documents are saved or there are no open documents. Terminate.
}

...

// Document saving finished
-(void)document:(NSDocument *)doc didSave:(BOOL)didSave contextInfo:(void  *)contextInfo
{
  if (didSave)  // Save button pressed
  {
    NSDocumentController *dc = [NSDocumentController sharedDocumentController];
    NSInteger nextIndex = [(__bridge NSNumber *)contextInfo integerValue];
    for (NSInteger i = nextIndex; i < [[dc documents] count]; i++)
    {
      Document *doc = [[dc documents] objectAtIndex:nextIndex];
      if ([doc isDocumentEdited])
      {
        // Save next unsaved document
        [doc saveDocumentWithDelegate:self
                      didSaveSelector:@selector(document:didSave:contextInfo:)
                          contextInfo:(__bridge void *)([NSNumber numberWithInteger:nextIndex + 1])]; // Next document
        return;
      }
    }
    [NSApp replyToApplicationShouldTerminate:YES];    // All documents saved. Terminate.
  }
  else [NSApp replyToApplicationShouldTerminate:NO];  // Saving canceled. Terminate canceled.

}

于 2014-07-03T12:33:08.530 に答える