Skip navigation.
 
mlIs NSDocument's Saving Message Flow Threaded?
FROM : Jonathan Dann
DATE : Sat Feb 16 23:54:02 2008

Hi Guys,

I've overridden -
canCloseDocumentWithDelegate:shouldCloseSelector:contextInfo: to 
display a custom NSAlert if any of the text files that my NSDocument 
subclass manages are not saved.

The problem is, if the user tries to close the window and very quickly 
presses return to select the default response of "Save All Files" the 
app crashes when [self close] is called.  If they wait a second or two 
then no crash happens.  The "saveAllFiles" method writes the text 
files to the disk and then saves the NSDocument model, which holds all 
the file references.

From my logs I can see that the [self close] causes the document to 
be dealloc'd before -dataOfType:error: can be called.  With NSZombie 
enabled I get the following log output

2008-02-16 16:57:25.803 Scribbler[697:10b] *** -[ESDocument 
_saveDocumentWithDelegate:didSaveSelector:contextInfo:]: message sent 
to deallocated instance 0xea625c0

Where the instance 0xea625c0 is the ESDocument that is being saved, 
then closed.

Could this be a threading issue with the way NSDocument saves itself, 
even though I haven't put any threaded code in my app at all? I ask 
this as the time interval between hitting command-W and return seems 
to matter.

Here's the relevant code from my NSDocument:

- (IBAction)saveAllFiles:(id)sender;
{
   NSLog(@"%p %s",self,__func__);
   for (ESNode *node in self.projectFiles) {
       if (node.isEdited) {
           NSError *writeError;
           if (![node writeBodyToFileError:&writeError]) {
               NSLog(@"%p %s %@",self,__func__,writeError);
               [self presentError:writeError];
           }
       }
   }
   
   [self saveDocument:nil];
}

- (void)unsavedFilesAlertDidEnd:(NSAlert *)alert returnCode:
(NSUInteger)returnCode contextInfo:(void *)contextInfo;
{
   [alert release];

   if (returnCode == NSAlertSecondButtonReturn)
       return;
   if (returnCode == NSAlertFirstButtonReturn) {
       [self saveAllFiles:nil];
       [self close]; // THIS IS THE CULPRIT
   }
   if (returnCode == NSAlertThirdButtonReturn)
       [self close]; // close without saving
}

- (void)canCloseDocumentWithDelegate:(id)delegate shouldCloseSelector:
(SEL)shouldCloseSelector contextInfo:(void *)contextInfo;
{
   NSLog(@"%p %s",self,__func__);
   BOOL canClose = YES;
   
   for (ESNode *node in self.projectFiles) {
       if (node.isEdited) {
           canClose = NO;
           break;
       }
   }
   
   if (!canClose) {
       NSAlert *alert = [[NSAlert alloc] init]; // released in didEndSelector
       [alert setMessageText:NSLocalizedString(@"ThereAreUnsavedFiles",@"")];
       [alert 
setInformativeText:NSLocalizedString
(@"ThereAreUnsavedFileExplanation",@"")];
       [alert addButtonWithTitle:NSLocalizedString(@"SaveAll",@"")];
       [alert addButtonWithTitle:NSLocalizedString(@"Cancel",@"")];
       [alert addButtonWithTitle:NSLocalizedString(@"DontSave",@"")];
       [alert beginSheetModalForWindow:[self windowForSheet] 
modalDelegate:self 
didEndSelector
:@selector(unsavedFilesAlertDidEnd:returnCode:contextInfo:) 
contextInfo:nil];
   }
   
   objc_msgSend(delegate,shouldCloseSelector,self,canClose,contextInfo);
}

Thanks in advance, this has got be stumped.

Jon

Related mailsAuthorDate
mlIs NSDocument's Saving Message Flow Threaded? Jonathan Dann Feb 16, 23:54
mlRe: Is NSDocument's Saving Message Flow Threaded? Scott Stevenson Feb 17, 02:20
mlRe: Is NSDocument's Saving Message Flow Threaded? Jonathan Dann Feb 17, 14:02
mlRe: Is NSDocument's Saving Message Flow Threaded? David Dunham Feb 17, 22:50
mlRe: Is NSDocument's Saving Message Flow Threaded? Scott Stevenson Feb 18, 23:27
mlRe: Is NSDocument's Saving Message Flow Threaded? Jonathan Dann Feb 19, 00:17