Minimal document-based app

  • Dear list,

    I'm trying to understand how the things in Cocoa works but I'm
    struggling with one thing. I saw
    http://cocoawithlove.com/2010/09/minimalist-cocoa-programming.html and
    http://casperbhansen.wordpress.com/2010/08/15/dev-tip-nibless-development/
    and I think I somewhat understood.

    Now, I would like to do the same but for a "Document-based
    application". Please, does anyone know of a tutorial or example akin
    to the ones above? Alternatively, what do I need to do to make it
    work? I think I need to create NSDocumentController - but how does it
    relate to NSApplication? And I create NSDocument from there? Frankly,
    I'm bit lost...

    Thank you very much in advance!
  • I see no merit in trying to make a "minimal" document based app, whatever that is. It's usually misguided to try and build UI in code, it saves you nothing and makes it much harder to get anywhere.

    Just start a new Cocoa app and use the project template for a document based app. It gives you the necessary starting points, which though it adds a nib, it's extremely small. There is nothing to be gained by going some other route.

    --Graham

    On 30/04/2012, at 7:47 AM, ecir hana wrote:

    > Dear list,
    >
    > I'm trying to understand how the things in Cocoa works but I'm
    > struggling with one thing. I saw
    > http://cocoawithlove.com/2010/09/minimalist-cocoa-programming.html and
    > http://casperbhansen.wordpress.com/2010/08/15/dev-tip-nibless-development/
    > and I think I somewhat understood.
    >
    > Now, I would like to do the same but for a "Document-based
    > application". Please, does anyone know of a tutorial or example akin
    > to the ones above? Alternatively, what do I need to do to make it
    > work? I think I need to create NSDocumentController - but how does it
    > relate to NSApplication? And I create NSDocument from there? Frankly,
    > I'm bit lost...
    >
    > Thank you very much in advance!
  • If nothing else, it would explain to me how things works, 20 lines of
    code would help me better than 20 documentation pages. There tutorials
    above certainly did the explaining very well.

    Also, I don't really want to argue whether there is merit or not - I
    would be more thankful for the eventual tutorial or code sample.

    On Tue, May 1, 2012 at 8:08 AM, Graham Cox <graham.cox...> wrote:
    > I see no merit in trying to make a "minimal" document based app, whatever that is. It's usually misguided to try and build UI in code, it saves you nothing and makes it much harder to get anywhere.
    >
    > Just start a new Cocoa app and use the project template for a document based app. It gives you the necessary starting points, which though it adds a nib, it's extremely small. There is nothing to be gained by going some other route.
    >
    > --Graham
    >
    >
    > On 30/04/2012, at 7:47 AM, ecir hana wrote:
    >
    >> Dear list,
    >>
    >> I'm trying to understand how the things in Cocoa works but I'm
    >> struggling with one thing. I saw
    >> http://cocoawithlove.com/2010/09/minimalist-cocoa-programming.html and
    >> http://casperbhansen.wordpress.com/2010/08/15/dev-tip-nibless-development/
    >> and I think I somewhat understood.
    >>
    >> Now, I would like to do the same but for a "Document-based
    >> application". Please, does anyone know of a tutorial or example akin
    >> to the ones above? Alternatively, what do I need to do to make it
    >> work? I think I need to create NSDocumentController - but how does it
    >> relate to NSApplication? And I create NSDocument from there? Frankly,
    >> I'm bit lost...
    >>
    >> Thank you very much in advance!
    >
  • On 29 Apr 2012, at 22:47, ecir hana wrote:

    > Dear list,
    >
    > I'm trying to understand how the things in Cocoa works but I'm
    > struggling with one thing. I saw
    > http://cocoawithlove.com/2010/09/minimalist-cocoa-programming.html and
    > http://casperbhansen.wordpress.com/2010/08/15/dev-tip-nibless-development/
    > and I think I somewhat understood.
    >
    > Now, I would like to do the same but for a "Document-based
    > application". Please, does anyone know of a tutorial or example akin
    > to the ones above? Alternatively, what do I need to do to make it
    > work? I think I need to create NSDocumentController - but how does it
    > relate to NSApplication? And I create NSDocument from there? Frankly,
    > I'm bit lost…
    I appreciate the intention here.
    I would start by creating a NSDocumentBased app using the Xcode template and examining it.
    This app is fully functional even though it contains just the document class and the nib.
    The reason it works can be found in info.plist under CFBundleDocumentTypes.
    This defines the NSDocument class to use.

    In MainMenu.xib you can see that File New sends newDocument: up the responder chain.
    This passes up the chain to NSApplication which (having loaded Info.plist) knows to create an instance of your document class.
    To create a document in code just send newDocument: up the responder chain with a nil targeted action
    [NSApplication sendAction:@selector(newDocument:) to:nil from:self]

    Regards

    Jonathan Mitchell
  • On May 1, 2012, at 12:28 AM, ecir hana wrote:

    > If nothing else, it would explain to me how things works, 20 lines of
    > code would help me better than 20 documentation pages. There tutorials
    > above certainly did the explaining very well.

    But it won't teach you how document-based Cocoa apps are actually constructed.

    I would instead suggest understanding how nibs work, and how the document architecture is put together. Rather than focusing on finding an example that bucks convention, read the source to an example that adheres to it.

    >
    > Also, I don't really want to argue whether there is merit or not - I
    > would be more thankful for the eventual tutorial or code sample.

    Sorry, this isn't a reasonable demand. This is a discussion forum about Cocoa; you should anticipate that the participants will discuss your question from the perspective of Cocoa programmers.

    --Kyle Sluder
  • On 1 May 2012, at 2:28 AM, ecir hana wrote:

    > If nothing else, it would explain to me how things works, 20 lines of
    > code would help me better than 20 documentation pages. There tutorials
    > above certainly did the explaining very well.

    Every few months, a beginner comes who wants to skip NIBs to "see how it works." Please understand why experienced developers advise against this, even though they understand the impulse.

    NIBs _are_ how it works. They don't contain or generate code. They don't contain or generate scripts. They don't exercise much of the API you're trying to use. They contain archived objects and their connections.

    Their effects can (often) be mimicked in code, but by the same token, Objective-C can be mimicked in assembly. It is useful to understand a bit of assembly when you use a high-level language, but except in special circumstances, nobody advocates writing programs in it. And in the case of compiling Objective-C, at least the translation passes (notionally) through assembly code.

    Similarly, it is useful to understand how NIBs are reconstituted into objects, but one must understand that the underlying mechanism is reconstitution, not executing code that simulates reconstitution. Unlike the translation of a high-level language, there is no executable layer through which reconstitution passes. (At least in the sense you mean.)

    NOTE: On iOS, it is frequently useful to build object hierarchies in code, but the Cocoa Touch API is designed to make that easy. Even there, most designs take the form of reconstituting objects from NIBs.

    — F
  • What Fritz said.

    Unlike other graphical UI layout tools, Interface Builder is central to Cocoa development, not simply a shortcut for newbies or a way to get started quickly. Anyone who thinks developing without Interface Builder is a purer path to understanding Cocoa has already missed the point.

    _murat

    On May 1, 2012, at 7:50 AM, Fritz Anderson wrote:

    > On 1 May 2012, at 2:28 AM, ecir hana wrote:
    >
    >> If nothing else, it would explain to me how things works, 20 lines of
    >> code would help me better than 20 documentation pages. There tutorials
    >> above certainly did the explaining very well.
    >
    > Every few months, a beginner comes who wants to skip NIBs to "see how it works." Please understand why experienced developers advise against this, even though they understand the impulse.
    >
    > NIBs _are_ how it works. They don't contain or generate code. They don't contain or generate scripts. They don't exercise much of the API you're trying to use. They contain archived objects and their connections.
    >
    > Their effects can (often) be mimicked in code, but by the same token, Objective-C can be mimicked in assembly. It is useful to understand a bit of assembly when you use a high-level language, but except in special circumstances, nobody advocates writing programs in it. And in the case of compiling Objective-C, at least the translation passes (notionally) through assembly code.
    >
    > Similarly, it is useful to understand how NIBs are reconstituted into objects, but one must understand that the underlying mechanism is reconstitution, not executing code that simulates reconstitution. Unlike the translation of a high-level language, there is no executable layer through which reconstitution passes. (At least in the sense you mean.)
    >
    > NOTE: On iOS, it is frequently useful to build object hierarchies in code, but the Cocoa Touch API is designed to make that easy. Even there, most designs take the form of reconstituting objects from NIBs.
    >
    > — F
  • On May 1, 2012, at 8:50 AM, Fritz Anderson wrote:

    > NIBs _are_ how it works. They don't contain or generate code. They don't contain or generate scripts. They don't exercise much of the API you're trying to use. They contain archived objects and their connections.

    True, but the beginner may not have the slightest clue as to what those objects in Interface Builder are and what functionality they provide and how they should be properly connected. I have often found that once you understand a class and its methods by reading the documentation again and again and even doing some coding, then when you look at it in Interface Builder a light will go on and you will exclaim eureka, now I understand what this is trying to tell me! But for me it has NEVER been the other way around. I have NEVER learned a concept first Interface Builder and have it make sense.

    I have often thought that Interface Builder was created by very gifted programmers who knew the underlying objects and API and to them it all makes perfect sense but they are completely oblivious to the fact that it makes almost no sense to a beginner. Apple has done an incredible job with the Cocoa API, documentation, and developer tools but the learning curve can still be overwhelming.

    My advice to a beginner is start very small and work your way up. Read the documentation, get a good book like Cocoa Programming for Mac OS X Third Edition by Hillegass, and start working your way through the examples. There are no shortcuts. Hillegass covers the document architecture in Chapter 10 starting on page 157 which is almost half way through the book.

    Maybe it is just me, but that has been my experience.

    --Richard
  • > Unlike other graphical UI layout tools, Interface Builder is central to Cocoa development, not simply a shortcut for newbies or a way to get started quickly. Anyone who thinks developing without Interface Builder is a purer path to understanding Cocoa has already missed the point.

    Actually, there are a lot of commercial developers who hard-code their entire UIs.  I'm at something of a loss to see why myself, but they do it, and they swear it's the best way.  Ironically, one of the reasons often given is "easier internationalisation" vs xibs.

    Though this does happen more often with iOS than Mac OS, from what I've seen.  There may be some paradigms refusing to shift with ex- or co-Android developers.  Nonetheless it's demonstrably possible.
  • On May 1, 2012, at 12:46 PM, Wade Tregaskis wrote:

    > Actually, there are a lot of commercial developers who hard-code their entire UIs.  I'm at something of a loss to see why myself, but they do it, and they swear it's the best way.  Ironically, one of the reasons often given is "easier internationalisation" vs xibs.
    > Though this does happen more often with iOS than Mac OS, from what I've seen.  There may be some paradigms refusing to shift with ex- or co-Android developers.  Nonetheless it's demonstrably possible.

    I haven’t heard of it with any Mac apps, except for ugly Qt or Java apps.

    It’s kind of understandable on iOS because user interfaces tend to be simpler (especially since windows never have to resize) and a lot of apps use custom UI elements instead of sticking with the standard ones.

    —Jens
  • On 1 May 2012, at 20:46, Wade Tregaskis wrote:
    >
    > Actually, there are a lot of commercial developers who hard-code their entire UIs.  I'm at something of a loss to see why myself, but they do it, and they swear it's the best way.  Ironically, one of the reasons often given is "easier internationalisation" vs xibs.

    I use xibs of course but I quite often apply my bindings in code for more complex views.
    I find it much easier to track down bindings' issues in code than through the Xcode GUI.

    I think that knowing how to do things in code such as establish a window, configure a view hierarchy and establish target/action relationships are primary knowledge even if they are not a primary means of implementation.

    Jonathan Mitchell
  • Thank you all for the replies!

    As I said above, I don't want the question to be whether I should better
    use NIBs, or whether Cocoa is more suitable than assembler. I somewhat know
    already what the role of NIB is, that it can save time and so on. What I
    would like to know is what to do if I was not using NIBs, i.e. if I wanted
    to build as much as possible by hand.

    To put it in other words, imagine I wanted to go to some city and was
    asking about the best spots for hitchhiking. I know it's faster to get
    there by a car and that I can use a train. And please, let's not argue
    whether I should be hitchhiking in the first place.

    Now, I have some code to share!

    Please, I think I managed to write an app which seems to be working but I
    would like to check whether I missed something. Here what I did:

    - I have to use a bundle. That is, a folder with the following structure:
    Contents
    Contents/Info.plist
    Contents/MasOS/<executable>

    - Info.plist has to have:
    CFBundleExecutable for <executable>
    CFBundleName for the name of top-most folder (i.e. the bundle filename)
    CFBundleDocumentTypes - which I don't yet understand and will get do it
    bellow

    - then, the other interesting thing I found out is that I don't need to
    write AppDelegate (!). So, my main.m looks like:
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
        NSApplication * application = [NSApplication sharedApplication];
        <a menu item which fires newDocument:>
        [application run];

    - then, and this is the interesting bit, newDocument: gets automatically
    routed to my NSDocumentClass from Info.plist and there I create the window,
    the model, etc.:
    - (id)init
    {
      self = [super init];
      if (self) {
          NSRect contentSize = NSMakeRect(0.0f, 0.0f, 480.0f, 320.0f);
          window = [[NSWindow alloc] initWithContentRect:contentSize
    styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:YES];
          <...>
          [window makeKeyAndOrderFront:self];
      }
      return self;
    }

    And when I hit apple-n, the new window pops-up! I also have to implement
    dataOfType: and readFromData: - that comes next.

    But I have lots of questions:

    - I saw that Xcode named the Info.plist differently (it prepends my project
    name to it) - is it ok just to call it Info.plist? Is there any convention?

    - this CFBundleDocumentTypes - what if I wanted to have only one kind of
    documents? Does it have to be an array as well? What is the absolute
    minimum every CFBundleDocumentTypes must contain?

    - is it really the case that I don't need the AppDelegate? It currently
    makes sense to me but maybe I'm missing something?

    - I don't want to put the window in init, where else should I put it? Does
    NSDocument have an equivalent of applicationDidFinishLaunching, i.e. when
    the document is created is there any callback fired?

    - new windows are positioned over the previous ones - I know this is
    because of that NSMakeRect() - the application created using Xcode (with
    NIBs) put every new window slightly to the right, slightly below the
    previous window - what is responsible for it? The NIB?

    Lots of questions, I know. Thank you in advance for any help with answering
    these!
  • On May 2, 2012, at 7:19 AM, ecir hana wrote:

    > - I saw that Xcode named the Info.plist differently (it prepends my project
    > name to it) - is it ok just to call it Info.plist? Is there any convention?

    https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BP
    RuntimeConfig/Articles/ConfigFiles.html


    > - this CFBundleDocumentTypes - what if I wanted to have only one kind of
    > documents? Does it have to be an array as well? What is the absolute
    > minimum every CFBundleDocumentTypes must contain?

    https://developer.apple.com/library/mac/#documentation/CoreFOundation/Refer
    ence/CFBundleRef/Reference/reference.html


    > - is it really the case that I don't need the AppDelegate? It currently
    > makes sense to me but maybe I'm missing something?

    http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html

    > - I don't want to put the window in init, where else should I put it? Does
    > NSDocument have an equivalent of applicationDidFinishLaunching, i.e. when
    > the document is created is there any callback fired?

    https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Appl
    icationKit/Classes/nsdocument_Class/Reference/Reference.html


    > - new windows are positioned over the previous ones - I know this is
    > because of that NSMakeRect() - the application created using Xcode (with
    > NIBs) put every new window slightly to the right, slightly below the
    > previous window - what is responsible for it? The NIB?

    It is called window cascading.

    https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Appl
    icationKit/Classes/nswindowcontroller_Class/Reference/Reference.html


    You should also read this.

    http://cocoawithlove.com/2008/03/cocoa-application-startup.html

    --Richard
  • On May 2, 2012, at 6:19 AM, ecir hana <ecir.hana...> wrote:

    > As I said above, I don't want the question to be whether I should better
    > use NIBs, or whether Cocoa is more suitable than assembler. I somewhat know
    > already what the role of NIB is, that it can save time and so on. What I
    > would like to know is what to do if I was not using NIBs, i.e. if I wanted
    > to build as much as possible by hand.

    Nonetheless, you should not do “as much as possible by hand” if what you’re looking for is a deeper understanding of the frameworks. The Cocoa frameworks are designed to be used with nibs.

    One of the core principals in Cocoa development is “don’t fight the framework.” Trying to develop a Cocoa application without using Interface Builder is fighting the framework.

    Learn how things work with Interface Builder first, then do things manually in the few cases where you have to. You’ll get up the learning curve a lot faster and you’ll be a lot more productive at the same time.

      -- Chris
  • On May 2, 2012, at 6:19 AM, ecir hana <ecir.hana...> wrote:

    > - I saw that Xcode named the Info.plist differently (it prepends my project
    > name to it) - is it ok just to call it Info.plist? Is there any convention?

    Xcode is actually prepending the target name, not the project name: A project can have multiple targets, creating a new project really creates a new empty project and then adds a target of the desired type with the same name.

    Using a «TargetName»-Info.plist as the name also helps to emphasize that it’s a source file, not something copied wholesale into the output. For example, build settings using ${SETTING_NAME} syntax in «TargetName»-Info.plist are expanded, for example

        <key>CFBundleIdentifier</key>
        <string>com.example.${PRODUCT_NAME:rfc1034identifier}</string>

    is used (assuming you specified a bundle identifier prefix of com.example) instead of hard-coding the app name into the bundle identifier.

    > - I don't want to put the window in init, where else should I put it? Does
    > NSDocument have an equivalent of applicationDidFinishLaunching, i.e. when
    > the document is created is there any callback fired?

    This is a case where I think trying to do everything “by hand” may be inducing some confusion and is definitely causing you to do more work than you probably need to.

    The method -[NSDocumentController newDocument:] is what creates and presents a new untitled document; its documentation indicates what it sends to do so, and the documentation for those methods do the same in turn. In the end -[NSDocument makeWindowControllers] and -[NSDocument showWindows] are used to present the document’s human interface.

    As you check out the documentation, you’ll see that by default, -[NSDocument makeWindowControllers] expects -[NSDocument windowNibName] to return the name of a nib file to use for the document’s human interface. In a lot of cases you’ll want a separate NSWindowController subclass, but even in those cases you’ll want it to use a nib (by initializing it with -[NSWindowController initWithWindowNibName:]) rather than a programmatically-wired-up window.

    In essence, don’t make more work for yourself than you need to. What Interface Builder does for you is basically this:

      Class1 *object1 = [[Class1 alloc] init];
      Class2 *object2 = [[Class2 alloc] init];
      Class3 *object3 = [[Class3 alloc] init];

      owner.outlet1 = object1;
      owner.outlet2 = object2;
      owner.outlet3 = object3;

      object1.property1 = owner;
      object1.property2 = object2;

      object2.property1 = object1;
      object2.property2 = object3;

      object2.target = owner;
      object2.action = @selector(anAction:);

      object3.target = firstResponder;
      object3.action = @selector(anotherAction:);

      [owner awakeFromNib];
      [object1 awakeFromNib];
      [object2 awakeFromNib];
      [object3 awakeFromNib];

    and so on. (Interface Builder actually uses archiving so it’ll use -initWithCoder: not -init, but the gist is clear.)

    It really won’t teach you much about Cocoa to write dozens of lines of code like this by hand — plus you’ll wind up having to do a lot of extra work to get everything to look like it does when you drag it (pre-configured) out of the library in Interface Builder.

    This is why people in the Cocoa community have the reaction we do when developers new to Cocoa ask how to put together interfaces without using Interface Builder, and why “don’t tell me not to, just tell me how” doesn’t generally get a good reception.

      -- Chris
  • I feel that there should be a long blog +video post that new devs
    should be pointed to everytime this question(view/bad choice) crops up
    that keeps all of the details of the many emails points that could be
    like an Apple best of doc.

    I know for sure that I have gone that route as well and still need to
    get back to IB when I try again at deving.

    Nick

    On Wed, May 2, 2012 at 3:51 PM, Chris Hanson <cmh...> wrote:
    > On May 2, 2012, at 6:19 AM, ecir hana <ecir.hana...> wrote:
    >
    >> - I saw that Xcode named the Info.plist differently (it prepends my project
    >> name to it) - is it ok just to call it Info.plist? Is there any convention?
    >
    > Xcode is actually prepending the target name, not the project name: A project can have multiple targets, creating a new project really creates a new empty project and then adds a target of the desired type with the same name.
    >
    > Using a «TargetName»-Info.plist as the name also helps to emphasize that it’s a source file, not something copied wholesale into the output. For example, build settings using ${SETTING_NAME} syntax in «TargetName»-Info.plist are expanded, for example
    >
    >    <key>CFBundleIdentifier</key>
    >    <string>com.example.${PRODUCT_NAME:rfc1034identifier}</string>
    >
    > is used (assuming you specified a bundle identifier prefix of com.example) instead of hard-coding the app name into the bundle identifier.
    >
    >> - I don't want to put the window in init, where else should I put it? Does
    >> NSDocument have an equivalent of applicationDidFinishLaunching, i.e. when
    >> the document is created is there any callback fired?
    >
    > This is a case where I think trying to do everything “by hand” may be inducing some confusion and is definitely causing you to do more work than you probably need to.
    >
    > The method -[NSDocumentController newDocument:] is what creates and presents a new untitled document; its documentation indicates what it sends to do so, and the documentation for those methods do the same in turn. In the end -[NSDocument makeWindowControllers] and -[NSDocument showWindows] are used to present the document’s human interface.
    >
    > As you check out the documentation, you’ll see that by default, -[NSDocument makeWindowControllers] expects -[NSDocument windowNibName] to return the name of a nib file to use for the document’s human interface. In a lot of cases you’ll want a separate NSWindowController subclass, but even in those cases you’ll want it to use a nib (by initializing it with -[NSWindowController initWithWindowNibName:]) rather than a programmatically-wired-up window.
    >
    > In essence, don’t make more work for yourself than you need to. What Interface Builder does for you is basically this:
    >
    >  Class1 *object1 = [[Class1 alloc] init];
    >  Class2 *object2 = [[Class2 alloc] init];
    >  Class3 *object3 = [[Class3 alloc] init];
    >
    >  owner.outlet1 = object1;
    >  owner.outlet2 = object2;
    >  owner.outlet3 = object3;
    >
    >  object1.property1 = owner;
    >  object1.property2 = object2;
    >
    >  object2.property1 = object1;
    >  object2.property2 = object3;
    >
    >  object2.target = owner;
    >  object2.action = @selector(anAction:);
    >
    >  object3.target = firstResponder;
    >  object3.action = @selector(anotherAction:);
    >
    >  [owner awakeFromNib];
    >  [object1 awakeFromNib];
    >  [object2 awakeFromNib];
    >  [object3 awakeFromNib];
    >
    > and so on. (Interface Builder actually uses archiving so it’ll use -initWithCoder: not -init, but the gist is clear.)
    >
    > It really won’t teach you much about Cocoa to write dozens of lines of code like this by hand — plus you’ll wind up having to do a lot of extra work to get everything to look like it does when you drag it (pre-configured) out of the library in Interface Builder.
    >
    > This is why people in the Cocoa community have the reaction we do when developers new to Cocoa ask how to put together interfaces without using Interface Builder, and why “don’t tell me not to, just tell me how” doesn’t generally get a good reception.
    >
    >  -- Chris
  • Thank you all very much, it is much clearer to me now. I'm diving into
    documentation now...
previous month april 2012 next month
MTWTFSS
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30            
Go to today