Why is applicationWillFinishLaunching in my NSApplicationDelegate class never called? - objective-c

main.m
#import <Cocoa/Cocoa.h>
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **) argv);
}
CoolClass.h
#import <Cocoa/Cocoa.h>
#interface CoolClass : NSObject <NSApplicationDelegate> {
}
- (void) applicationDidFinishLaunching : (NSNotification *) aNotification;
#end
CoolClass.m
#import "CoolClass.h"
#implementation CoolClass
- (void) applicationDidFinishLaunching : (NSNotification *) aNotification {
NSLog(#"THIS SHOULD BE PRINTED TO THE DEBUG CONSOLE");
}
#end
I tried this with "applicationWillFinishLaunching" as well, but still no luck. Any help at all would be appreciated. Thanks.

What you're missing is that adopting the protocol makes objects of kind CoolClass ready to function as delegates of any NSApplication object (provided you follow through on the declaration and implement all required methods of the protocol). Declaring conformance to the protocol also prevents compiler warnings when you set instances of the class as an application's delegate.
But for a specific application object (say, the shared NSApplication object that Cocoa creates for you) to know to send messages from the protocol to a specific CoolClass object, you must set the object you want to receive those messages as the specific application object's delegate.
What this means is that some time before the messages you want to receive would be sent by the application, something needs to instantiate a CoolClass object - call it c - and tell the application, "Hey, your delegate is c over here, so send delegate messages to the little feller from now on."
What that boils down to is that these lines of code must execute before the application finishes launching:
CoolClass *c = [[CoolClass alloc] init];
[[NSApplication sharedApplication] setDelegate:c];
The easiest way to have this happen is to let Interface Builder do the work for you: let the MainMenu nib instantiate your CoolClass and also set the cool class object as the application's delegate when the nib is loaded, as others have suggested.
To do so, open MainMenu.xib. Drag a Custom Object into the xib and change its class to CoolClass in the inspector. Ctrl-drag (or right-click drag) from the application object in the xib to the CoolClass object and choose "delegate". Save, build, and run.

You should define your CoolClass as applications delegate in Interface Builder (Ctrl+Drag from App instance to your CoolClass instance

applicationDidFinishLaunching is an instance method, not a class method. That is, you'll need an instantiation of your class to receive that message. Plus, it can't be just -any- instantiation; your application needs to know about your instantiation and know that it's supposed to send delegate messages to it. The easiest and most common way to do this is...
First, you'll instantiate your CoolClass. Open your application's MainMenu.nib file in Interface Builder. Drag an "Object" (it'll look like a blue cube) out of the Library window. Select it and use the Identity tab of the Inspector to change its class from NSObject to CoolClass. Now, you have an instance of your CoolClass.
Now, you'll set that instance as the application's delegate. Control-drag from "Application" (still in Interface Builder) to your new instance of CoolClass. A window will pop up (showing outlets of Application that could be connected to your object). Choose "delegate". Now your application has an instance of your CoolClass set as its delegate, and thus, your applicationDidFinishLaunching will run.

I appreciate you may be trying to learn from scratch, but why did you not just create a new project using one of the XCode templates? It sets all this up for you to begin with. Life involves enough debugging without having to add more atop it!

To start at the beginning: your call to NSApplicationMain should be wrapped in an NSAutoreleasePool. You will be in trouble if you don't do that.

Related

Calling a method from another class WITHOUT creating a new instance

This is a common topic but, in my case there is one thing I don't understand that I can't find explained in the other asked questions.
Here is the gist of what I'm trying to do:
User clicks a button and something like this is called:
#implementation FirstClass
-(void)clickedButton
{
[SecondClass changeText];
}
And then in SecondClass is:
#implementation SecondClass
- (void)changeText {
[myLabel setText:#"text"];
}
So when the user clicks the button, the text property in myLabel in SecondClass changes to "text".
The only problem I have with this is calling [SecondClass changeText] on the existing instance of SecondClass. Since I'm not initializing the CCNodes programmatically (they are all automatically loaded upon running the app), I don't know where or how SecondClass is initialized. I'm using SpriteBuilder to build this project.
Any help would be appreciated. Thanks!
So, you have two instaces -- one with a button, and one with a label. I'm assuming they are both descendants of NSViewController or otherwise manage underlying views.
The problem is, you found no way to address second instance containing label from the method of first instance.
You need to define a property in first instance's class:
#property(weak) SecondClass *secondInstance;
And then in button clicked method:
-(void)clickedButton
{
[self.secondInstance changeText];
}
There is one issue left: who is responsible to set first instance's property that we defined? This depends on who did create both of them, probably just app delegate or enclosing controller, you know that better.
UPD: If both of the controllers are created by AppDelegate:
#import "FirstClass.h"
#import "SecondClass.h"
#interface AppDelegate ()
// case A - manual
#property(strong) FirstClass *firstInstance;
#property(strong) SecondClass *secondInstance;
// case B - declared in xib
//#property(weak) IBOutlet FirstClass *firstInstance;
//#property(weak) IBOutlet SecondClass *secondInstance;
#end
#implementation AppDelegate
...
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
// Create them
self.firstInstance = [[FirstClass alloc] init...];
self.secondInstance = [[SecondClass alloc] init...];
// Or maybe they are declared in MainMenu.xib, then you do not create them
// by hand, but must have outlets for both. See case B above.
// Connect them
self.firstInstance.secondInstance = self.secondInstance;
...
}
Note that class is not the same as an object (instance). Class is a named collection of methods, mostly for the instance. In Objective-C, class is not just a name, but an object too, so you can call a method on it (i.e. send an message to the class object). But here we always talk about objects (instances), so forget about classes – we hold objects via strong properties or weak outlets, depending on how they were created, and operate on objects, never on classes.
In objective C, the methods are either instance methods or class methods. As the name suggests, the instance methods require an instance of the class to work, whereas the class methods can be used with just the name of the class. What you need here is a class method. Just change the following line in your code:
#implementation SecondClass
- (id)changeText {
to
#implementation SecondClass
+ (id)changeText {
This will change the method from an instance method to a class method.

How can I stop ARC releasing objects when I dont want it to? [duplicate]

I am having a problem with memory management in objective C. Ive been reading through the Advanced Memory Management Programming Guide but I cannot find a solution to my problem with the possible exception of abandoning ARC altogether and managing the memory manually.
Here is the problem:
I have a Controller class that Ive made, that holds information on what to do at specific times.
The Controller class tells the rest of the app to play a video (for example). The video plays fine. When the video finishes playing, the Controller class knows what to do next.
Unfortunately the Controller class is released and deallocated by ARC almost as soon as the video starts playing. So by the time the video ends, the app calls the Controller class to see what it should do next, and the whole thing crashes. I get an EXC_BAD_ACCESS because the class is no longer in memory.
I get that ARC is releasing my Controller class because after it has told the video to start playing, its not doing anything. But I want to keep hold of that class until I need it again.
I am declaring this class as a property, like so:
#property (strong, nonatomic) Controller * controller;
But despite this, ARC keeps releasing the class as soon as its not doing anything.
EDIT:
Ive moved this property into the App Delegate. But ARC is still releasing it. I cant turn this into a Singleton, as I need the potential to have multiple copies of this class.
How can I stop ARC releasing objects when I dont want it to??
Is it possible to keep an object in memory while its not doing anything?
Is this possible at all? Or should I abandon ARC and just do memory management manually?
Use a singleton pattern so that Controller looks after its own lifetime and exists app-wide. This shared instance will exist from when it's first requested until the app terminates and ARC will not release it arbitrarily.
Controller.h:
#interface Controller : NSObject
+ (Controller *)sharedInstance;
#end
Controller.m:
#import "Controller.h"
static Controller *_instance = nil;
static dispatch_once_t _onceToken = 0;
#implementation Controller
+ (Controller *)sharedInstance {
dispatch_once(&_onceToken, ^{
_instance = [[Controller alloc] init];
});
return _instance;
}
// You could add this if you want to explicitly destroy the instance:
+ (void)destroy {
_instance = nil;
_onceToken = 0;
}
Your controller is getting dealloc'ed when the detailViewController is dealloc'ed. Hence, you must move the handle of your controller and define in it the any of the following :
MasterViewController or your application's RootViewController
OR
AppDelegate
OR
Create a singleton as answered by "trojanfoe"
I stumbled upon this case several times when working with UITableViews. I created a private #property (strong) id *yourObjectRetain and assigned my object to it. An array for multiple objects will also work.

Calling release on an object which is on the call stack of current thread

I am new to cocoa, since I am programming cocoa app I always get confused how to release an object which tells its delegate that I am done. And the listener tries to release it.
So I have an AppController which lunches a updateCheckWindowController and also acts as a delegate to it so that when updateCheckWindow ends it can take further action (in my case release it). The UpdateCheckWindowController calls the delegate when window ends, so that call goes to AppController's method which tries to release the calling Object updateCheckWindowController.
Since AppController was the only one retaining it, calling a release should destroy the updateCheckWindowController , but updateCheckWindowController object is currently on the callStack because it is the one calling delegate method on AppController and AppController tries to release it. Its kind of circular call
How does it work in objective-c ? this looks like a pretty bad pattern unlike there is a fair justification for that. Or is my way of doing it is incorrect ?
You're judgement is probably right that there is a better pattern to use that avoids the circular call altogether.
If you have a view controller that is presented for a short period of time and then should be released when dismissed, you can use this method of UIViewController:
presentViewController:animated:completion:
You can autorelease the view controller you are presenting before you present it. Calling this method will retain it. When the controller should be dismissed, it can tell its delegate and the delegate can call
dismissViewController:animated:completion.
When the delegate dismisses it then it will be released.
Is this the situation or is it more complicated?
This could be as simple as using autorelease instead of release. Autorelease often doesn't perform an actual release until the call stack is unwound.
The call stack does not pose any problems here. As long as UpdateCheckWindowController does not do anything after the call after which it's released, you'll be fine.
See bbrame's answer for how you might organize your controller life cycles better. I will just explain the memory management consequences of your original architecture.
So, if I got your situation right, you have something like the following. It's going to work fine even if the object may be released before returning back to someMethod provided that you're not referencing self in any way after the delegate method call.
Note that your view controller is probably still referenced by UIKit by the time delegate method returns. That is, if that view controller is still part of the navigation stack. In this case, you shouldn't worry about it being released too early, it'll only happen after your methods return and the control goes back to the run loop.
#interface AppController: NSObject
#property (nonatomic, strong) UpdateCheckWindowController *ctrl;
- (void)updateCheckWindowController;
- (void)iAmDoneReleaseMe;
#end
#implementation AppController
- (void)updateCheckWindowController {
UpdateCheckWindowController *ctrl = [[UpdateCheckWindowController alloc] initWithDelegate:self];
// ...
// Retain the controller
self.ctrl = ctrl;
}
- (void)iAmDoneReleaseMe {
self.ctrl = nil;
}
#end
#interface UpdateCheckWindowController: NSObject
// Make it weak so we don't have a retain cycle
#property (nonatomic, weak) AppController *delegate;
#end
#implementation UpdateCheckWindowController
- (void)someMethod
{
// do all the finishing work here
// ...
// now call the delegate that will release us
[self.delegate iAmDoneReleaseMe];
// don't do anything else here and you'll be fine
}
#end

Unable to access App Delegate property

I'm trying to access a property in my app delegate from another class (something I thought would be rather simply) but I'm having troubles in doing so. My files currently look like this:
LTAppDelegate.h
#import <Cocoa/Cocoa.h>
#import "Subject.h"
#interface LTAppDelegate : NSObject <NSApplicationDelegate, NSOutlineViewDelegate, NSOutlineViewDataSource, NSMenuDelegate> {
}
#property Subject *selectedSubject;
#end
LTAppDelegate.m
#synthesize selectedSubject;
The value for selectedSubject is then set inside applicationDidFinishLaunchingin LTAppDelegate.m. Now I'm wanting to get access to this from another class that I have, which is called LTTableViewController and is setup like so:
LTTableViewController.h
#import <Foundation/Foundation.h>
#import "LTAppDelegate.h"
#import "Subject.h"
#import "Note.h"
#interface LTTableViewController : NSObject{
NSMutableArray *notesArray;
LTAppDelegate *appDelegate;
Subject *s;
}
-(IBAction)currentSubjectDetails:(id)sender;
#end
LTTableViewController.m
#import "LTTableViewController.h"
#implementation LTTableViewController
- (id)init
{
self = [super init];
if (self) {
appDelegate = ((LTAppDelegate *)[[NSApplication sharedApplication] delegate]);
s = [appDelegate selectedSubject];
NSLog(#"Test Subject: %#", [s title]);
}
return self;
}
-(IBAction)currentSubjectDetails:(id)sender{
NSLog(#"Selected Subject: %#", [s title]);
}
After inserting various NSLog() messages it would appear that the init method of LTTableViewController is called before applicationDidFinishLaunchingis called in LTAppDelegate. Based on that it makes sense that the "Test Subject" NSLog() in LTTableViewController.m init displays null; however, the 'currentSubjectDetails' method is linked to a button on the interface and when that is pressed after the app is finished loading, the NSLog() message still returns null.
Is there anything obvious I'm missing here. I feel like I'm being a little stupid and missing something really basic.
Similar issue is described here http://iphonedevsdk.com/forum/iphone-sdk-development/11537-viewcontroller-called-before-applicationdidfinishlaunching.html Adding this kind of functionality in the constructor is usually not recommended. Generally, I'd suggest using parameters and not relying on hidden dependencies as those will necessarily depend on the order of execution and you lose the help of the compiler to avoid invalid values. View controller initializers should not be used to store mutable references since view controllers are initialized automatically by predefined constructors, and you cannot pass parameters to them this way.
If you need to access the app delegate, then obtain it, perform operations on it and drop the reference. Try not to cache it, you'll very likely introduce hidden issues. I suggest you hook into the appear-disappear cycle if the viewed contents depend on any kind of current state.
Well, s does not exist, since it is set to null in init, so -currentSubjectDetails prints null. It is not a good idea to set your private variables in the constructor if they depend on other objects.
Rather, let the other objects explicitly tell your controller that it should use that Subject (e.g., treat s as a property).
Or, just query ((LTAppDelegate *)[[NSApplication sharedApplication] delegate]); every time.
-applicationDidFinishLaunching called when e.g. all nib's object initialized, so launching will be ended after construction of views related stuff. This means that constructors of nib's objects wouldn't use any other nib's objects (your delegate and controller initializing with nib, right?).
Try to use -awakeFromNib instead of constructors, I think it will called after construction of both objects.
If you are trying to avoid often calls of ((LTAppDelegate *)[[NSApplication sharedApplication] delegate]) I'll recommend to pass it as method parameter, in function stack. Cyclic references defense and some flexibility.

Can't access UI from a delegate?

I got this code:
GrooveOnDownload *dlg = [[GrooveOnDownload alloc] init];
NSURLDownload *dw = [[NSURLDownload alloc] initWithRequest:request delegate:dlg];
It starts the download in a delegate class with outlets for UI controls. But for some reason controls don't respond to direct messages from the delegate.
//Header of the delegate
#interface GrooveOnDownload : NSObject {
IBOutlet id downloadButton;
//...
//Implementation
//...
[downloadButton setEnabled:FALSE]; // Doesn't work
//...
Any ideas?
It is my fourth day of Mac development so I don't know much about the platform.
Edit : 2010-05-28 01:03:41.486 GrooveOnLite[3303:a0f] Download button = (null)
Edit 2 :
Edit 3 :
I miss Windows .....
Edit 4
In Win32 you send one window message to the button. Everything is handled by WndProc loop. It is damn simple. In Mac you have this magical interface builder which somehow gets all that crap working. The delegate gets called by some withcraft magic. The rest of the classes are connected by some 'magical' force. In windows there is an tmain function which is the entry point. That's it! No retarded outlets and such shit.
I know it sounds obvious, but is everything connected correctly in Interface Builder?
Edit
If the download is on a separate thread, then fbrereto is correct and you'll need to perform the selector on the main thread. Your code would need to be changed to look like this:
[downloadButton performSelectorOnMainThread:#selector(setEnabled:)
withObject:[NSNumber numberWithBool:NO]
waitUntilDone:YES];
A few notes: in Objective-C the keyword NO is used instead of FALSE. It's a primitive type, so in order to use it here we had to box it in a NSNumber object. The waitUntilDone argument does exactly what you would expect, and you can change that to NO if you'd rather not wait.
Edit 2
Here's a more complete code example about how to accomplish what I think you want, which is to reuse a single instance of GrooveOnDownload from your app delegate. I'm assuming that your app delegate class is called GrooveOnLiteAppDelegate.
// GrooveOnLiteAppDelegate.h
#interface GrooveOnLiteAppDelegate : NSObject
{
IBOutlet GrooveOnDownload *grooveOnDownload;
// other properties go here
}
// your method signatures go here
#end
// GrooveOnLiteAppDelegate.m
#implementation GrooveOnLiteAppDelegate
- (void)mySuperAwesomeMethod
{
// it's up to you to figure out what method to put this in and
// how to call it
NSURLDownload *dw = [[NSURLDownload alloc] initWithRequest:request delegate:grooveOnDownload];
}
#end
Given that code in your app delegate, you'll have an outlet in IB that you can connect to your GrooveOnDownload object in IB. If you do that, then grooveOnDownload will be a pointer to that object.
All UI calls have to be made on the main thread; if the download is happening in the background your delegate may be getting notified on a thread other than the main one, in which case a call to a UI element would have to be done through something like -[NSObject performSelectorOnMainThread:withObject:waitUntilDone:modes: or another related API.