NSApplicationMain: What happens to parameters?

Discussion in 'Mac Programming' started by ajbrehm, Mar 31, 2007.

  1. macrumors 6502

    Joined:
    Aug 14, 2002
    Location:
    Zurich, Switzerland
    #1
    As it should Xcode sets up the main function in main.m as follows:

    Code:
    int main(int argc, char *argv[])
    {
    	return NSApplicationMain(argc,  (const char **) argv);
    }
    
    Perhaps this is a stupid question but the answer is really not obvious to me. How do I get the values in argc and argv from within my classes?

    argc should be 1, at least, and argv[0] should be the parth to my program. And within main in main.m that is easily verified. But how do I read them later?

    Also, how do I define a method that runs when the program starts? I can press a button and make a method do something, but how can I get a method to run without having the user do anything to create an event?
     
  2. macrumors G4

    Eraserhead

    Joined:
    Nov 3, 2005
    Location:
    UK
    #2
    You can put it in an init or an awakeFromNib method.
     
  3. thread starter macrumors 6502

    Joined:
    Aug 14, 2002
    Location:
    Zurich, Switzerland
    #3
    Thanks. That worked.

    Any idea for the argc and argv parameter problem? What happened to them when in "return NSApplicationMain(argc, (const char **) argv);"?
     
  4. macrumors G4

    Eraserhead

    Joined:
    Nov 3, 2005
    Location:
    UK
    #4

    It is used in Command Line applications, which accept arguments from the command line, and it is used in C which Obj-C is based on, which I guess is why they are there. If you make a command line App in Obj-C you modify main.m so can use them...
     
  5. thread starter macrumors 6502

    Joined:
    Aug 14, 2002
    Location:
    Zurich, Switzerland
    #5
    Yes, but how do I use them?

    The first parameter contains the path to my binary, which is useful. The second should contain the path to the file (associated with my program) I double-clicked.
     
  6. macrumors G4

    Eraserhead

    Joined:
    Nov 3, 2005
    Location:
    UK
    #6
    No idea, can't you get these values in a different way?
     
  7. macrumors member

    Joined:
    Feb 18, 2007
    Location:
    Eindhoven
    #7
    If you know which command line options you want (e.g.: appname -path pathname), the easiest way is:
    NSString *path = [[NSUserDefaults standardUserDefaults] stringForKey:mad:"path"];

    If not, use the -(NSArray *)arguments method from NSProcessInfo.

    Wittegijt.
     
  8. thread starter macrumors 6502

    Joined:
    Aug 14, 2002
    Location:
    Zurich, Switzerland
    #8

    This is weird.

    The first parameter is indeed the path to my binary. But the second parameter is not the file I double-clicked on. Instead I get the following:

    "-psn_0_336986113"

    When I do a "myprogram file.ext" in the command line I get the following two command line parameters:

    1. path to my binary
    2. "file.ext"

    When I double-click on file.ext in the Finder (.ext files are associated with myprogram) I get the following two command line parameters:

    1. path to my binary (as expected)
    2. "-psn_0_336986113" (or some other number)

    The second I did not expect. How do I get the path to the file I double-clicked? How does that work in Cocoa?
     
  9. thread starter macrumors 6502

    Joined:
    Aug 14, 2002
    Location:
    Zurich, Switzerland
    #9
    I got my program to display everything it could read in [NSUserDefaults standardUserDefaults] but the path to the file I double-clicked to open was not in it.

    If the path to my file is not the second command line parameter or in the defaults, where is it?

    I tried finding out in the TextEdit example source but it was too well-hidden.

    This is surprisingly complicated and the documentation does not even touch the subject. Yet all Cocoa applications out there can open files double-clicked in the Finder if associated with them.
     
  10. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #10
    The filename is not on the command line. When your application is running your NSApplication delegate (if you have one) will be asked to open any files double clicked on via:

    Code:
    - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
    Note that this can get called over and over if you have multiple files to open. If you are using the document architecture this all get's handled automatically for you. If you are writing an application that can open documents you should probably be using the Document Based Application template in XCode.

    You can see the description for this in the Delegate Methods section of the NSApplication documentation.
     
  11. thread starter macrumors 6502

    Joined:
    Aug 14, 2002
    Location:
    Zurich, Switzerland
    #11
    This sounds a lot more difficult than on other platforms. :-(

    That means my application has to consider two different possibilities regarding the file it is supposed to open. One for having been started from a command line and one for the Finder.

    I'll try the above.

    Thanks.
     
  12. thread starter macrumors 6502

    Joined:
    Aug 14, 2002
    Location:
    Zurich, Switzerland
    #12
    The documentation keeps referring to "delegates" as if everybody is supposed to know what they are. :-(

    Also, openFile does not seem to return a string.

    This really is surprisingly complicated. Usually (on Windows and UNIX) the path to the file double-clicked can be found in the second command line parameter. What does my program need to be told its process number for?

    Thanks for your help, but somehow I am unable to make the step from

    Code:
    - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
    
    to getting the path for my file that I expected to find in argv[1].

    In fact, none of the methods in NSApplication seem to return a string.
     
  13. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #13
    delegation is a standard design pattern. It's not even really a Cocoa specific thing: .Net uses then a lot too, so yes you are supposed to know what they are. You keep referring to other platforms. Cocoa is not supposed to be cross platform. It's for writing Mac applications. If you want to write something cross platform it's probably easier to write a standard POSIX (or whatever) command line app and the wrap a true Cocoa GUI round it.

    Anyway back on topic! Apple provide an amazing amount of very good documentation. Have you tried reading it? For example they explain delegates here. If you've not read the entire Cocoa Fundamentals guide then do that now. That's not a Aprils fool joke: it's well after midday here.

    The basic idea is that you create a custom object and set that as the application delegate. In that object you implement a method with the signature I provided previously. NSApplication will then automatically call your method passing the filename as the named arguement.
     
  14. thread starter macrumors 6502

    Joined:
    Aug 14, 2002
    Location:
    Zurich, Switzerland
    #14
    Wow!

    How did you know that I never tried reading the documentation I was referring to? And how did you so clearly deduce that when I compared Cocoa to other platforms I was obviously referring to cross-platform development?


    I have to thank the other two guys for helping me with the command line problem. It's good to see that people often explain something in simple terms rather than demonstrate how much more they know about the issue as such.
     
  15. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #15
    I didn't say you hadn't read it. I asked if you had. You may have considered it to be a rhetorical question but it was not intended as one.

    I simply thought that as you were asking a basic question about a core Cocoa concept that you might find some advantage in taking some time to read or re-read the basic core Cocoa conceptual documentation that is essential to understanding Cocoa.
     
  16. thread starter macrumors 6502

    Joined:
    Aug 14, 2002
    Location:
    Zurich, Switzerland
    #16
    Ok. No harm, no foul; I am sure.

    But seriously, I don't want to open the file, I only want to find out the path to it. Surely there must be an easier method like on other platforms?

    Also, I'm not sure I have asked a question about a core Cocoa concept. The concept I am looking for is fairly universal and it works the same way on Windows and UNIX. I don't think it can be so much more complicated on a Mac, no?
     
  17. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #17
    It would be the same if you wrote a pure C command line app. Once you decide to use Cocoa you are deciding to use that Framework and all that brings. You don't have to open the file. Just return NO from the delegate method.
     
  18. thread starter macrumors 6502

    Joined:
    Aug 14, 2002
    Location:
    Zurich, Switzerland
    #18
    So there really is no simple way to find out the path to the file double-clicked?
     
  19. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #19
    I really don't see what is so difficult about doing it via the delegate. See the absolutely minimal example attached. This is a non-document based app that "opens" files *.test. If you drop any .test file on it's Dock icon or (once you've run the app once) double click in any .test file it'll tell you the path.

    Edit: forgot to attach file :eek:
     

    Attached Files:

  20. thread starter macrumors 6502

    Joined:
    Aug 14, 2002
    Location:
    Zurich, Switzerland
    #20
    Thanks!

    Weirdly enough it works on its own. But when I add the method to my program with the only change of the name of the text field, it doesn't do anything.

    Since other methods can update the text field in question I assume the text field works. But

    Code:
    - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
    
    seems never to be called.
     
  21. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #21
    Did you check out the nib file? You need to ensure that there is an instance of the new class created somewhere (I did it in the nib) and that the instance is set as the NSApplication delegate (again I did it in the nib)...
     
  22. thread starter macrumors 6502

    Joined:
    Aug 14, 2002
    Location:
    Zurich, Switzerland
    #22
    In your nib file I find an instance of the class AppDelegate. In my nib file is an instance of my class.

    Does the class have to be called "AppDelegate"? I tried that, created the class, the files, and the instance in Interface Builder, but it still didn't do anything.
     
  23. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #23
    The name is irrelevant. It obviously has to be an instance of the correct class (but the name is just a name). It then has to be connected as the NSApplication delegate. The FileOwner icon is the NSApplication (in this case, this is not always true). Do the normal to connect it as a delegate (ctrl-drag from FileOwner to the instance and choose delegate).

    Edit it add: in case the start of that is not clear: the class can be called anything you like. The instance can also be renamed in Interface Builder without altering the class (in case you have two instances of the same class and you want to be able to tell them apart for instance).
     
  24. thread starter macrumors 6502

    Joined:
    Aug 14, 2002
    Location:
    Zurich, Switzerland
    #24
    That worked! Thanks.

    It's not obvious.
     
  25. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #25
    Well you don't have to do it that way. You could have your instance set itself as the application delegate programatically when it wakes from the bib. Or do you mean the way you do the connection? As that's covered in the tutorials. You eventually think it's second nature!
     

Share This Page