In Cocoa, what is the purpose of the main.m class? - objective-c

It just sits there... How do I run code independently of UI actions (as in, not only in response to a button push)? I'm trying to initialize some objects and run some scripts BEFORE i awakeFromNib. How do I do this?

In Cocoa, what is the purpose of the main.m class?
None, because there isn't one.
For one thing, the .m file is not the class. Neither is the .h. The practice of putting a class's #interface in a .h (header) file and its #implementation in a .m (implementation) file is a convention, nothing more. It's a good convention, but it's not enforced by the language.
So, a .m file contains zero or more class implementations. Usually, it's exactly one. Sometimes it's two, where the other is a small private class whose #interface is also in the same file.
main.m contains no classes. It usually only contains one function, which is named main.
main comes from C (of which Objective-C is a superset), and is the entry point of the program: It's where the program starts running. Everything happens here, or in a function called from here. A command-line tool will usually exit here as well, by main returning.
Most main functions in Cocoa apps are the default one that comes with the project template; this implementation simply tail-calls NSApplicationMain, which sets up the shared NSApplication object and starts it running. That function never returns; when the user quits a Cocoa app, the process simply exits.
You may want to read this list of important facts about Cocoa and Objective-C that I wrote. It sounds like you have some misconceptions (probably brought over from another framework you're more familiar with) that that list can clear up for you.
How do I run code independently of UI actions (as in, not only in response to a button push)?
That depends on when you are trying to do it. A periodic action, for example, would be a job for a timer.
I'm trying to initialize some objects and run some scripts BEFORE i awakeFromNib. How do I do this?
You could do it in initWithCoder:, which is sent to every non-view-layer object instantiated from an archive, including yours. Nibs are archives, too.
You might also consider being the application delegate and implementing a applicationWillFinishLaunching: method.
A third way would be to stuff the code in main. Note that practically any Cocoa code here is likely to log “no autorelease pool” warnings unless you wrap it in an #autoreleasepool statement; other solutions don't have this problem because NSApplication has already created an autorelease pool for you.

main.m is what starts the application - to run things befor nibs load put it in main.m before the NSApplication is created.

Related

Why Apple's sample code project IKImageViewDemo does not have an AppDelegate class?

I have studying how to use IKImageView in my app. I downloaded the following demo from Apple site.
https://developer.apple.com/library/mac/samplecode/IKImageViewDemo/Introduction/Intro.html#//apple_ref/doc/uid/DTS10004049
One thing I do not understand is: This project has only implemented a Controller class.
#interface Controller : NSObject
{
...
I do not understand how does it work at all. If I create a new project in XCode, it will usually generate an AppDelegate class which implements NSApplicationDelegate interface.
I do not know if I understand the mechanism correctly.
Does the following steps describe how it works?
1) In info.plist it specifies the main bundle is MainMenu.xib.
2) the Window is binded to the Controller like so
3) When the application starts, it loads the Windows from the MainMenu.xib and the Controller class takes over the windows interaction from there.
It's really old sample code. It predates Xcode project templates generating an app delegate for you.
Back then, early Xcode and ProjectBuilder (the old name for it)
Left it up to you to do that.
Lots of older sample code has this sort of thing. As long as things get kickstarted by nib loading, magic happens, objects are instantiated and connected
If you have a simple controller that inherits from NSObject and it has a proxy in you main nib file, it will get created. If you also connect its proxy as delegate to some view or control in the nib, all of that happens.
You don't technically need an object that is the delegate of you NSApplication object. But in reality it is a good best practice and any non trivial app will have that and a lot more.
There's a lot of magic that happens when the C function NSApplicationMain() is called at the launch of your app.
The old and in many ways out if date book Cocoa in a Nutshell covers this well.
Yeah you pretty much describe how it works and what it's doing.
It's relying on the fact that NSApplicationDelegate is an informal protocol and it doesn't declare that Controller conforms to it and is using the NIB to kick-start the app.

XCode/Cocoa Objective-C - A couple questions

Sorry for the stupid post, but I am new to Objective-C programming and Cocoa and have a couple of questions which I can't find the answers to, I'm hoping someone can enlighten me.
Firstly, in XCode, when using the Interface builder, when I want to create a new object I drag the object to my 'assets'. However I can't specify methods or anything without manually creating a new class file. Is there any point using the interface builder's 'object'?
The first app I built to test things with, I put most of the code in the AppDelegate class files. Research has shown me that the AppDelegate's purpose is simply handling application events like launching and closing. Was I wrong in putting the methods in this class? Does it make any difference?
Finally, if I have several class files created, each handling their own functionality with an interface built and linked to the classes, then what do I do with the 'main' file? It seems to me that the 'main' file and 'appdelegate' class files will be for the most case left as-is?
I hope that makes sense. Again i'm sorry for the silly-sounding questions but I can't find any answers.
Thanks in advance everyone!
Firstly, in XCode, when using the Interface builder, when I want to create a new object I drag the object to my 'assets'. However I can't specify methods or anything without manually creating a new class file.
Sure you can. Just set the class of the object using the inspector.
Note that you can only connect nib objects to an outlet or action. You can't specify any random methods, nor should you—the whole point of the IBOutlet, IBOutletCollection, and IBAction keywords is to declare in code that these properties/methods are used by a nib.
Is there any point using the interface builder's 'object'?
Yes, but pretty rarely. Usually you create objects in code and connect outlets to them.
The application's delegate is one object you may want to create in the MainMenu or MainWindow nib, if you build your application that way (the iOS templates have changed away from it for some reason).
The first app I built to test things with, I put most of the code in the AppDelegate class files. Research has shown me that the AppDelegate's purpose is simply handling application events like launching and closing. Was I wrong in putting the methods in this class?
Probably. The application's delegate generally should only handle business relating to the NS/UIApplicationDelegate protocol.
On the flip side, it's OK to make your root view controller the application's delegate, if it makes sense to do so (and the NS/UIApplicationDelegate implementation code is not too voluminous). The question you have to answer—and only you can answer it for your application—is whether you are making your root view controller the application's delegate or the application's delegate the root view controller. If in doubt, keep them separate.
Does it make any difference?
Long-term, yes. It's very easy, especially in the class of the application's delegate, to create a Big Ball of Mud class—one without well-defined and clearly-delineated responsibilities. Take dynamite to such a class as soon as possible.
Finally, if I have several class files created, each handling their own functionality with an interface built and linked to the classes, then what do I do with the 'main' file? It seems to me that the 'main' file and 'appdelegate' class files will be for the most case left as-is?
Yes. They're boiler-plate.
If you haven't written any code in the application's delegate (or have removed everything you had put there into new and better-delineated classes), such that all that's left are empty method bodies or none at all, you can safely remove the application's delegate. You can always create it again later if you change your mind.
Note that if you delete your application delegate class, you should also change the main.m file—or the MainMenu/MainWindow nib, if you have one—to not refer to it. Your application won't build if your UIApplicationMain call (or any other code) refers to a class that doesn't exist, and it will crash if your MainMenu/MainWindow nib (or any other nib) refers to a class that doesn't exist.
There is no shame in your application having a delegate if you need it to, but if you don't, removing it and the class you were using for it eliminates future temptation to stuff code there or use it to store third-order globals.
The point of using objects in interface builder is to connect methods of the object to UI elements.
It partly depends on what your methods are doing, but for the most part the app delegate class is going to be left alone. It isn't an actual requirement (your program will work either way) but it is common practice because it generally creates more maintainable code. The app delegate should just handle the application events ( using other classes to do any complex logic or heavy lifting ).
The 'main' file will most likely not change. I can't think of any reason to do so, but I wouldn't rule it out for some advanced cases.
To be honest I only used the Object thing in IB once, when I wanted a separate object to have some UI bindings.
About the app delegate and main file, yes, you'll leave them as-is most of the time. But if you try to do something besides test apps you'll need to handle open events to, for example, connect to a server, ask the user for a review, increment some launch counter, etc... Those are just examples!
The main file I advise you to left it alone and use the object oriented tools provided. You should have a view controller hierarchy, isolate your views from the data, and use the view controller to comunicate between view and model. Read about MVC if you want more info on how your application should be organized.

Connecting actions works. Connecting outlets doesn't

I have a XIB file with my controls in it, loaded in the Interface Builder (Xcode 4.0.2 on Snow Leopard).
The file's owner is set to, let's say, the someClassController class, and I've also added (in the Interface Builder) an NSObject instance of someClass, as well.
I've managed to link e.g. a button with an action in someClassController or someClass - and it works for both of them.
However, whenever I link an outlet to ANY of them, it fails to show up; and NSLog reports NULL pointers.
Hint : My issue here could be much more complicated than it seems, since both my someClass and someClassController classes inherit other classes, which inherit other classes and so on (I'm dealing with a huge-to-chaotic codebase, and I don't really know what else could be helpful to post)... However, I would still like to hear your opinion on what might be going wrong in such a case...
When you see problems like this, it's almost always because you have more than one object of the kind that has the outlet. The one in the nib whose outlet you connected is not the one that is examining its outlet.
To investigate this, add statements in the object's initializer method(s) and possibly awakeFromNib to log the value of self.
Some (or all, or none) of the objects may be created in nibs, and some (or all, or none) of them may be created in code; objects in the latter group won't trip awakeFromNib, since they didn't.
Either way, once you've inventoried what instances of the class you have, you can kill them off until you're left with the ones you want.
To add to Peter Hosey's answer, and after reading some more details in the other question you posted about this issue, here are some other factors to consider:
The File Owner class selected in the nib is completely ignored at runtime. It's there only for design-time convenience – for checking available actions and outlets.
Is there any chance you're finding nil pointers in -init? Outlets are connected after -init and before -awakeFromNib. They'll never be connected in -init.
I'm trying to understand the sequence of initialization (from your other post). It sounds like you are creating a new instance of your CTTabContents subclass, and passing it to your CTBrowserWindowController subclass's -addTabContents: method. Then the CTBrowserWindowController loads your objects from the nib.
Or, maybe that's wrong. You might be creating a instance of your CTTabContentsController subclass. Then that object is loading TabContents.xib.
It's important to track down where the nib is being loaded and which object is being provided as the file owner at that time.
Another question: are you using manual release/retain, automatic reference counting, or garbage collection?
Finally, I reiterate the importance of printing out the self pointer in your initialization methods. In addition to -init and -awakeFromNib, try other initialization methods like your CTTabContents subclass' -initWithFrame:. When you're discovering intermittent null pointers in the rest of your debugging, print out the self pointers then, too. You'll probably be seeing different values of self then, too.

How do I initialize a window in Objective-C?

For a Mac graphics application (not iPhone), I need something like a main method in Java, the first method that gets a program going. I've been looking at things like NSViewController and NSWindow object. I've looked around but can't find an answer to this seemingly easy question anywhere. (I am very new at this by the way)
Thanks
If you create a Cocoa project from one of the Xcode "Cocoa Application" templates, you'll get a main.m file that includes the usual startup code.
Try working through one of the tutorial projects that you'll find in the documentation.
If you are using the project templates, the startup code is in the ApplicationDelegate file. The main.m, for a Cocoa application, sets up the run loop, runs NSApplication (as you can see in the Info.plist file under the 'Principle class' key.
This then loads the nib file that is specified in the Info.plist file (under the 'Main nib file base name' key). The default is MainMenu.xib. Now have a look at this nib file.
This is already set up by the template to have a 'Files's Owner' of NSApplication (the class that loaded the nib) But There is also a blue block which represents the application delegate. This is already filled out with one delegate method one outlet.
The delegate method is applicationDidFinishLaunching: This method is called by the application. This is only one of the possible delegate methods that it can handle, but it is sent after the run loop is started but before the application receives any events. It is the common place to put your initialisation code. It is in here that you should start to set up your window, which you can get to using the pre-supplied window outlet.
This is just a quick summary. A handy referenece is on Cocoa With Love and Apple's Introduction to Application Architecture document.

How to find out which file gets run first in Xxode

In an Xxode project that has a lot of .h and .m files, how do you determine which file gets executed first?
The file that contains int main(int argc, char * argv[]); will get run first, since the main() function is the first function to get run. In pretty much every Xcode template project, that file is called "main.m".
edit
Usually, the main() function of a Cocoa Touch app is this:
int main(int argc, char *argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}
(Substitute NSApplicationMain() for UIApplicationMain() and remove the autorelease pool if you're writing a Mac app)
edit #2
I'm only interested in the file that gets run first from the classes folder
The simple answer is "The application delegate", then everything else.
The technical answer to that is that any objects in your MainMenu.xib (Mac) or MainWindow.xib (iOS) file will be instantiated first. Usually the objects in that file will be instantiated in the order in which they appear, but I don't think that's guaranteed.
So if you 3 have custom top-level objects in your MainWindow.xib file, then they'll all be instantiated at the same time (within reason). First their initWithCoder: methods will execute, then some time later their awakeFromNib methods will execute (which usually the safest "starting point" for that object).
The application delegate launch methods will happen somewhere along in there too (I believe in between initWithCoder: and awakeFromNib).
Cocoa and Cocoa-Touch apps are completely event-driven. It is not that the order the methods are executed can be understood by reading the source code files.
As Dave explained, the entry of the program is at the main function in main.m. It immediately calls UI/NSApplicationMain.
NS/UIApplicationMain is a function provided by Cocoa(-Touch). It watches the user interaction, and fires events accordingly.
For example, when the user clicks a button, the system calls automatically what you provided as the action method specified in the xib file.
Another example is the drawRect: method you provide: it's called when the system decides to draw an object onto the screen. It's very important that you don't actively draw to the screen. The system asks you to draw the screen, and you respond.
One important set of events are the ones which are called at the beginning of the program, like applicationDidFinishLaunching: or the ones which are called when a view is loaded from the xib file, viewDidLoad.
Aaron Hillegass made a great analogy of the situation: you're KITT and respond to Michael Knight's order, not the other way around. Well you need to be over certain age to understand this analogy...
Another thing that should get run first is in an App Delegate (Defined like so: NSObject <UIApplicationDelegate> and setup in the nib) the method applicationDidFinishLaunching
This is obviously not technically the first thing to be run. The main loop and whatever is in UIApplication will be executed first, but in general this is good starting point for iOS applications and the first place you really have control.
You can also create a class called like "Controller" and drag an NSObject into your nib and set the class to Controller. Then the method awakeFromNib will be called.
Either of these should be fine to set up your app.