Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document wont open if saved during opening #22

Open
colasbd opened this issue Feb 28, 2014 · 17 comments
Open

Document wont open if saved during opening #22

colasbd opened this issue Feb 28, 2014 · 17 comments

Comments

@colasbd
Copy link

colasbd commented Feb 28, 2014

Hi Mike!

I find this bug or feature (?).
During the opening of a document, I do some stuff and then save the document (with saveDocument:): the document won't open.

Here is a minimal example:

// .h
#import <Cocoa/Cocoa.h>
#import "BSManagedDocument.h"

@interface CBDDocument : BSManagedDocument

@end

and

// .m
#import "CBDDocument.h"

@implementation CBDDocument

- (id)initWithContentsOfURL:(NSURL *)url
                     ofType:(NSString *)typeName
                      error:(NSError *__autoreleasing *)outError
{
    self = [super initWithContentsOfURL:url ofType:typeName error:outError] ;

    if (self)
    {
        //[self saveDocument:self] ;    <--- this give a fatal crash because save is called not on the main thread

        [self performSelectorOnMainThread:@selector(saveDocument:)
                               withObject:self
                            waitUntilDone:YES] ;
    }

    return self ;
}


- (NSString *)windowNibName {  return @"CBDDocument"; }
+ (BOOL)autosavesInPlace {  return YES; }

@end

With this class, do the following:

  • create a new document
  • save it, name it "Test"
  • close it
  • open "Test"

It won't open.


Here is the context of my question.

Shall I use the saveDocument: method? If I [self.managedObjectContext save:NULL], is it enough for the document to be saved? (my doc is not a bundle)

(The problem for NSDocument is that if you [self.managedObjectContext save:NULL] then NSDocument will complain about another app having modified the document since the last save).

Thanks.

@mikeabdullah
Copy link
Collaborator

My suspicion is that you've got a deadlock here. I imagine opening the document takes a lock on the file (using NSFileCoordinator). Trying to save from within this code then tries to acquire the lock for a second time, deadlocking.

If so, your problem here is independent of BSManagedDocument, and down to how NSDocument is designed/implemented currently.

Are you able to confirm the deadlock from pausing in the debugger?

@colasbd
Copy link
Author

colasbd commented Mar 1, 2014

Thanks for your answer. I don't know what's a deadlock. How can I see it in the debugger?

@mikeabdullah
Copy link
Collaborator

If you don't know what a deadlock is, I suggest now is the time to improve your Computer Science knowledge and read up on the topic :-)

@colasbd
Copy link
Author

colasbd commented Mar 1, 2014

Yes... learning, learning, learning... I imagine it's a lock and someone has lost the key ;-)

@colasbd
Copy link
Author

colasbd commented Mar 1, 2014

How can I see it in the debugger?

@mikeabdullah
Copy link
Collaborator

I'm assuming the symptom is: your document never appears on-screen.

If so, after waiting a little, hit pause in Xcode. You should then be able to see the stack of all active threads. I imagine one of those will be deadlocked inside -saveDocument:

@colasbd
Copy link
Author

colasbd commented Mar 1, 2014

Yes you are right. (this is after 2/3 minutes)

capture decran 2014-03-01 a 18 53 22

@mikeabdullah
Copy link
Collaborator

Drag the slider to see the full trace

@colasbd
Copy link
Author

colasbd commented Mar 1, 2014

??
capture decran 2014-03-01 a 18 59 15
What do you mean?

PS : Can you imagine I have been coding for 6 month without knowing about po? Just came to know about it like 2 weeks ago!!!

@mikeabdullah
Copy link
Collaborator

At the bottom of the navigator view, there is a slider, which you can drag to expose more of the stack trace

@colasbd
Copy link
Author

colasbd commented Mar 1, 2014

So, you were 100% right it seems ;).
Thanks for this live mini-session on "how to use xcode for debugging" !

capture decran 2014-03-01 a 19 18 56

@mikeabdullah
Copy link
Collaborator

Some possible solutions then:

  • I have no idea what you're ultimately trying to achieve. Do you really need to save the document as soon as it is opened?
  • Override -[NSDocumentController makeDocument…] instead and do the save there
  • NSDocument offers some API for re-entrantly doing file coordination type stuff. It may be possible to avoid the deadlock using it

@colasbd colasbd closed this as completed Mar 3, 2014
@colasbd colasbd reopened this Mar 11, 2014
@colasbd
Copy link
Author

colasbd commented Mar 11, 2014

For information,

I tried to subclass NSDocumentController with

- (void)openDocumentWithContentsOfURL:(NSURL *)url
                              display:(BOOL)displayDocument
                    completionHandler:(void (^)(NSDocument *, BOOL, NSError *))completionHandler
{
    [super openDocumentWithContentsOfURL:url
                                 display:displayDocument
                       completionHandler:^void (NSDocument * theDoc, BOOL aBool, NSError * error)
     {
         completionHandler(theDoc, aBool, error) ;

         /*
          We save synchronously
          */
         dispatch_sync(dispatch_get_main_queue(), ^
                       {
                           [theDoc saveDocument:self] ;
                       }) ;


     }] ;
}

as well as

- (id)makeDocumentWithContentsOfURL:(NSURL *)url
                             ofType:(NSString *)typeName
                              error:(NSError *__autoreleasing *)outError
{
    Document * loadedDoc = [super makeDocumentWithContentsOfURL:url
                                                           ofType:typeName
                                                            error:outError] ;

    /*
     We save synchronously
     */
    dispatch_sync(dispatch_get_main_queue(), ^
                  {
                      [loadedDoc saveDocument:self] ;
                  }) ;

    return loadedDoc ;
}

but both still create a deadlock.

@colasbd
Copy link
Author

colasbd commented Mar 11, 2014

I have no idea what you're ultimately trying to achieve. Do you really need to save the document as soon as it is opened?

When a document is opened, sometimes some corrupted data needs to be fixed. I do it, but I want to save these fixes. So that the user won't remark anything.

@mikeabdullah
Copy link
Collaborator

I suspect your dispatch_sync is now causing a problem

  • if you're already on the main thread, dispatch_sync will instantly cause a deadlock
  • dispatch_sync will not magically cause saving to be synchronous
  • does your save even need to be synchronous?
  • is this event rare enough that you should actually inform the user in some fashion, and get their permission before saving?
  • it's pretty clear this issue is completely independent of BSManagedDocument. Probably worth your while asking a more general question about it of the world, perhaps even in the form of a simplified test document

@colasbd
Copy link
Author

colasbd commented Mar 12, 2014

Hi Mike,

First of all, thank you for helping me. I know you don't have to do this (and it is not related to BSManagedDocument). So, thanks!!

I agree with you, this is completely independent of BSManagedDocument. I have sent a message to the Apple mailing list (it's my first message, it's being moderated)... let's see. I will ask a question on SO. Do you see any other forum? (I am working alone)

To answer you remarks:

  • opening does not happen on the main thread (or I am missing something) ?

capture decran 2014-03-12 a 11 17 46

  • if I dispatch_async, I have a deadlock as well.
  • if I don't dispatch at all the saveDocument:, I get a crash (see below). The crash confirms that I am not on the main queue.
2014-03-12 11:21:52.942 MyApp[558:7003] *** Assertion failure in -[Document contentsForURL:ofType:saveOperation:error:], /Users/colas/MyDeveloper/MyApps/MyMainApps/My App/MyApp/Pods/BSManagedDocument/BSManagedDocument.m:313
2014-03-12 11:21:52.951 MyApp[558:7003] An uncaught exception was raised
2014-03-12 11:21:52.951 MyApp[558:7003] Somehow -contentsForURL:ofType:saveOperation:error: has been called off of the main thread (operation 0 to: /Users/colas/Desktop/Sans titre 2.MyApp)
2014-03-12 11:21:52.951 MyApp[558:7003] (
    0   CoreFoundation                      0x00007fff8731625c __exceptionPreprocess + 172
    1   libobjc.A.dylib                     0x00007fff8f598e75 objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff87316038 +[NSException raise:format:arguments:] + 104
    3   Foundation                          0x00007fff8aeb3d41 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 189
    4   MyApp                             0x00000001000d43b4 -[BSManagedDocument contentsForURL:ofType:saveOperation:error:] + 340
    5   MyApp                             0x00000001000d5433 __73-[BSManagedDocument saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke + 323
    6   AppKit                              0x00007fff91675955 -[NSDocument continueFileAccessUsingBlock:] + 234
    7   AppKit                              0x00007fff91675ded -[NSDocument _performFileAccessOnMainThread:usingBlock:] + 782
    8   AppKit                              0x00007fff91676a74 -[NSDocument performAsynchronousFileAccessUsingBlock:] + 481
    9   MyApp                             0x00000001000d52e3 -[BSManagedDocument saveToURL:ofType:forSaveOperation:completionHandler:] + 163
    10  AppKit                              0x00007fff916842bf __85-[NSDocument saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo:]_block_invoke_2 + 310
    11  AppKit                              0x00007fff916b1630 -[NSDocument _commitEditingThenContinue:] + 501
    12  AppKit                              0x00007fff916b17dd -[NSDocument _commitEditingWithDelegate:didSomethingSelector:contextInfo:thenContinue:] + 138
    13  AppKit                              0x00007fff91684177 __85-[NSDocument saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo:]_block_invoke + 524
    14  AppKit                              0x00007fff91674c47 -[NSDocument performActivityWithSynchronousWaiting:usingBlock:cancellationHandler:] + 66
    15  AppKit                              0x00007fff91683f5c -[NSDocument saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo:] + 169
    16  AppKit                              0x00007fff9167fba1 __67-[NSDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:]_block_invoke_31381 + 221
    17  AppKit                              0x00007fff91675012 -[NSDocument continueActivityUsingBlock:] + 323
    18  AppKit                              0x00007fff9167fab7 __67-[NSDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:]_block_invoke_21378 + 278
    19  AppKit                              0x00007fff9167eefd -[NSDocument _checkForFileChangesThenSave:saveAs:orCancel:] + 708
    20  AppKit                              0x00007fff9167f991 __67-[NSDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:]_block_invoke1375 + 536
    21  AppKit                              0x00007fff916aa48f -[NSDocument _checkAutosavingIgnoringSafetyChecksThenContinue:] + 116
    22  AppKit                              0x00007fff9167f33e __67-[NSDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:]_block_invoke_2 + 517
    23  AppKit                              0x00007fff916b1630 -[NSDocument _commitEditingThenContinue:] + 501
    24  AppKit                              0x00007fff916b17dd -[NSDocument _commitEditingWithDelegate:didSomethingSelector:contextInfo:thenContinue:] + 138
    25  AppKit                              0x00007fff9167f12a __67-[NSDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:]_block_invoke + 367
    26  AppKit                              0x00007fff91674c47 -[NSDocument performActivityWithSynchronousWaiting:usingBlock:cancellationHandler:] + 66
    27  AppKit                              0x00007fff9167efae -[NSDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:] + 128
    28  MyApp                             0x000000010003635e -[Document saveDocument:] + 206
    29  MyApp                             0x0000000100034f97 -[Document initWithContentsOfURL:ofType:error:] + 1319
    30  AppKit                              0x00007fff916b9fcb -[NSDocumentController makeDocumentWithContentsOfURL:ofType:error:] + 772
    31  AppKit                              0x00007fff916b9454 __80-[NSDocumentController openDocumentWithContentsOfURL:display:completionHandler:]_block_invoke_2838 + 51
    32  libdispatch.dylib                   0x00007fff8e38f1d7 _dispatch_call_block_and_release + 12
    33  libdispatch.dylib                   0x00007fff8e38c2ad _dispatch_client_callout + 8
    34  libdispatch.dylib                   0x00007fff8e38e09e _dispatch_root_queue_drain + 326
    35  libdispatch.dylib                   0x00007fff8e38f193 _dispatch_worker_thread2 + 40
    36  libsystem_pthread.dylib             0x00007fff8a3d0ef8 _pthread_wqthread + 314
    37  libsystem_pthread.dylib             0x00007fff8a3d3fb9 start_wqthread + 13
)
2014-03-12 11:21:52.953 MyApp[558:7003] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Somehow -contentsForURL:ofType:saveOperation:error: has been called off of the main thread (operation 0 to: /Users/colas/Desktop/Sans titre 2.MyApp)'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff8731625c __exceptionPreprocess + 172
    1   libobjc.A.dylib                     0x00007fff8f598e75 objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff87316038 +[NSException raise:format:arguments:] + 104
    3   Foundation                          0x00007fff8aeb3d41 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 189
    4   MyApp                             0x00000001000d43b4 -[BSManagedDocument contentsForURL:ofType:saveOperation:error:] + 340
    5   MyApp                             0x00000001000d5433 __73-[BSManagedDocument saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke + 323
    6   AppKit                              0x00007fff91675955 -[NSDocument continueFileAccessUsingBlock:] + 234
    7   AppKit                              0x00007fff91675ded -[NSDocument _performFileAccessOnMainThread:usingBlock:] + 782
    8   AppKit                              0x00007fff91676a74 -[NSDocument performAsynchronousFileAccessUsingBlock:] + 481
    9   MyApp                             0x00000001000d52e3 -[BSManagedDocument saveToURL:ofType:forSaveOperation:completionHandler:] + 163
    10  AppKit                              0x00007fff916842bf __85-[NSDocument saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo:]_block_invoke_2 + 310
    11  AppKit                              0x00007fff916b1630 -[NSDocument _commitEditingThenContinue:] + 501
    12  AppKit                              0x00007fff916b17dd -[NSDocument _commitEditingWithDelegate:didSomethingSelector:contextInfo:thenContinue:] + 138
    13  AppKit                              0x00007fff91684177 __85-[NSDocument saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo:]_block_invoke + 524
    14  AppKit                              0x00007fff91674c47 -[NSDocument performActivityWithSynchronousWaiting:usingBlock:cancellationHandler:] + 66
    15  AppKit                              0x00007fff91683f5c -[NSDocument saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo:] + 169
    16  AppKit                              0x00007fff9167fba1 __67-[NSDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:]_block_invoke_31381 + 221
    17  AppKit                              0x00007fff91675012 -[NSDocument continueActivityUsingBlock:] + 323
    18  AppKit                              0x00007fff9167fab7 __67-[NSDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:]_block_invoke_21378 + 278
    19  AppKit                              0x00007fff9167eefd -[NSDocument _checkForFileChangesThenSave:saveAs:orCancel:] + 708
    20  AppKit                              0x00007fff9167f991 __67-[NSDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:]_block_invoke1375 + 536
    21  AppKit                              0x00007fff916aa48f -[NSDocument _checkAutosavingIgnoringSafetyChecksThenContinue:] + 116
    22  AppKit                              0x00007fff9167f33e __67-[NSDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:]_block_invoke_2 + 517
    23  AppKit                              0x00007fff916b1630 -[NSDocument _commitEditingThenContinue:] + 501
    24  AppKit                              0x00007fff916b17dd -[NSDocument _commitEditingWithDelegate:didSomethingSelector:contextInfo:thenContinue:] + 138
    25  AppKit                              0x00007fff9167f12a __67-[NSDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:]_block_invoke + 367
    26  AppKit                              0x00007fff91674c47 -[NSDocument performActivityWithSynchronousWaiting:usingBlock:cancellationHandler:] + 66
    27  AppKit                              0x00007fff9167efae -[NSDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:] + 128
    28  MyApp                             0x000000010003635e -[Document saveDocument:] + 206
    29  MyApp                             0x0000000100034f97 -[Document initWithContentsOfURL:ofType:error:] + 1319
    30  AppKit                              0x00007fff916b9fcb -[NSDocumentController makeDocumentWithContentsOfURL:ofType:error:] + 772
    31  AppKit                              0x00007fff916b9454 __80-[NSDocumentController openDocumentWithContentsOfURL:display:completionHandler:]_block_invoke_2838 + 51
    32  libdispatch.dylib                   0x00007fff8e38f1d7 _dispatch_call_block_and_release + 12
    33  libdispatch.dylib                   0x00007fff8e38c2ad _dispatch_client_callout + 8
    34  libdispatch.dylib                   0x00007fff8e38e09e _dispatch_root_queue_drain + 326
    35  libdispatch.dylib                   0x00007fff8e38f193 _dispatch_worker_thread2 + 40
    36  libsystem_pthread.dylib             0x00007fff8a3d0ef8 _pthread_wqthread + 314
    37  libsystem_pthread.dylib             0x00007fff8a3d3fb9 start_wqthread + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException

@mikeabdullah
Copy link
Collaborator

It's important to make the distinction: those stack traces you've posted are an exception, not a crash

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants