How does Xcode setup a document based application?
Asked Answered
S

3

8

I am learning Cocoa and my understanding from reading the documentation is that when an application starts the following happens:

  1. A shared application instance is created.
  2. The main nib file is looked up from the applications property list so that the application knows which nib to load.
  3. the run loop is started.

This is fine and makes sense for s single windowed application however I am confused by what xcode does when a document based application is created.

In this case there are two nib files; the first contains the application menu and the second contains the window which represents the NSDocument subclass. when I run the application a new document window is opened automatically.

Based on my understanding of how the application works outlined above I don't understand how my application knows to open the document window once the menu nib has been looked up from the property list. There is no code generated to do this as far as I can see (except for the windowNibName method but where is this called from?)

Can anyone tell me what xcode does differently so that the application knows that it is document based and therefore needs to open a document window?

Update:

What I am trying to understand is how Xcode knows how to do something different if my application is set up as a document based application rather than a single window application. As far as I am aware there is no setting to specify this and Xcode doesn't appear to generate any code to give this different behaviour.

From reading the documents over the last couple of days I think I know how this works but am not sure:

  1. _NSApplication_has a delegate method applicationOpensUntitledFile which is called by the applications delegate.
  2. NSDocumentController is set as the applications delegate by default and the default implementation looks for the presence of the CFBundledTypeInfo to determine if the document is document based or not and responds as is appropriate for the application (I.E. YES for document based application and NO for single window applications).
  3. The majority of the time when a single window application is created the application delegate is replaced by a custom AppController anyway which usually wont contain a definition for the applicationOpenUntitledFile method as it is not appropriate for the type of application.

Hopefully any Cocoa experts can confirm if my understanding is correct or if I am barking up the wrong tree.

Sharkey answered 26/6, 2011 at 19:9 Comment(0)
A
5

When you create a document-based application, you get a few things:

  • A subclass of NSDocument
  • A new xib file for this document, in addition to MainMenu.xib
  • A CFBundleDocumentTypes entry in Info.plist, which tells the app about your NSDocument subclass

When your app opens, the shared NSDocumentController will create a new untitled document using the CFBundleDocumentTypes information.

For more information, read The Document-Based Application Project Template and the rest of the document-based applications guide.

Alvertaalves answered 26/6, 2011 at 19:17 Comment(8)
So basically the presence of the CFBundleDocumentTypes entry in my property list file determines wether or not NSApplication treats my program as a document based application or not?Sharkey
Essentially, yes. As I said, the shared NSDocumentController will use the CFBundleDocumentTypes to create a new document.Alvertaalves
If you add a breakpoint on -[NSDocumentController openUntitledDocumentAndDisplay:error:], you can see that it gets called automatically.Alvertaalves
Thank you. I have just tested this by creating an NSDocumentController subclass, overriding the method and placing a breakpoint in it. I also tried this in a non-document based application out of curiosity to see what happens and it does not get called. Do you know if this is because there is no CFBundleDocumentType in the plist of the single document application? Sorry to ask a lot of questions but I really like to understand how the plumbing of a system works before I use it rather than relying on the magic of the IDE.Sharkey
I think so, but I'm not completely sure. The documentation describes the details of a lot of this, but I can understand wanting to know more. I'd encourage you to read the guide I linked. An excerpt: "When a user chooses New from the File menu, an NSDocumentController object gets the appropriate NSDocument subclass from the CFBundleDocumentTypes property in the application’s information property list, allocates an instance of this class, and initializes this instance by invoking the NSDocument method initWithType:error:."Alvertaalves
Also, about breakpoints: if you don't want to (or can't easily) create a subclass, you can create a "symbolic breakpoint" (click the + button in the Breakpoints navigator in Xcode 4) for the symbol "-[NSDocumentController openUntitledDocumentAndDisplay:error:]" and it will break in the existing class.Alvertaalves
I have been reading the documentation (plus the class references) and they aren't very good at describing what's happening behind the scenes. The extract refers to connections that are made in interface builder and methods that are invoked when the user selects a menu item but I am after clarity on something that occurs in the application automatically without any user interaction or any code being written by myself. I appreciate all the help you have offered so far. Thanks also for the breakpoint tip.Sharkey
I agree, I think the documentation about this doesn't explain as much as it could. You will find some similar topics which are explained in more depth. You could also try asking questions on devforums.apple.com where you might get answers from Apple engineers, or at least other developers who have had the same issues.Alvertaalves
P
0

I assume your right. If you create a non based document application, add the document types informations in the -Info.plist and set the delegate of NSApplication in the main.m as following

int main(int argc, const char * argv[])
{
    [[NSApplication sharedApplication] setDelegate:[NSDocumentController sharedDocumentController]];
    [[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp topLevelObjects:nil];
    [NSApp run];
}

The behaviour seems to be the same as the the default Document-Based Application template.

Porfirioporgy answered 9/12, 2013 at 10:52 Comment(0)
A
0

No, your assumption is not right, look at the implementation of GNUstep version, in the NSApplication's finishLaunching method:

NSDocumentController    *sdc;
sdc = [NSDocumentController sharedDocumentController];
if ([[sdc documentClassNames] count] > 0)
{
  didAutoreopen = [sdc _reopenAutosavedDocuments];
}

So it create a instance of NSDocumentController automatically.

Abiding answered 10/7, 2014 at 8:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.