NSApplicaton delegate - applicationDidFinishLaunching - objective-c

I have declared a delegate for my cocoa application here :
MyAppDelegate.h
#interface MyAppDelegate : NSApplication {
}
- (void) applicationDidFinishLaunching:(NSNotification*) notice ;
#end
MyAppDelegate.m
#implementation MyAppDelegate
- (void) applicationDidFinishLaunching:(NSNotification*) notice {
NSLog(#"inside appdidfinishlaunching") ;
}
#end
I have linked the delegate outlet of File Owner to this object in IB.
Yet, this method is not getting called. I don't see any log messages from it.
Can you please suggest what is wrong ?

Your application delegate is not an application itself. It should inherit from NSObject, not NSApplication.
Why that matters
NSApplication is a singleton. Its init method always returns the first instanceĀ of NSApplication or any subclass, throwing away any subsequent objects you (or the nib loader) may be calling init on.
So you ended up setting your application object as its own delegate. The object you intended to make the delegate died in the second call to init, and the application object took its place.
Changing the application object to be an instance of your subclass would also have worked, but you'd still have the application as its own delegate, which is unclean and possibly dangerous (NSApplication may privately implement some of its delegate methods itself, as they're just notification handler methods). The only correct solution is to make your app delegate class not inherit from NSApplication.

Related

Referencing variables on NSApp delegate Cocoa

So I'm a little confused here. I have a Cocoa app, in the appdelegate header I'm declaring a NSDrawer that I've connected in Interfacebuilder and whose contentView I'm setting programmatically depending on the context. The contentviews contain Buttons that are connected to various functions in the Appdelegate.
#property (strong) IBOutlet NSDrawer *theDrawer;
When my app starts app, and I inspect it in the Debugger "theDrawer" is not nil and correctly instantiated by the Interfacebuilder. In the
Now if the user clicks any button it turns out that references to [[NSApp delegate] theDrawer] will be ignored because theDrawer is nil. which doesn't make sense to me. I tried fix this by specifically setting the delegate when the app launches.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[NSApp setDelegate:self];
}
I've checked that self.theDrawer is not nil at that point. But even after I set the delegate explicitly, any future calls to [[NSApp delegate] theDrawer] are nil.
How can I make sure to access variables on my App delegate? My understanding was that calls to NSapp delegate will return a unique instance of the app.
It seems that when a user clicks on a button that this creates a new thread and NSApp delegate will return nil for all variables.
Any help appreciated
The application delegate is properly set in main in main.m which you'll find in the "Supporting Files" folder of the project. Generally it's embedded in NSApplicationMain() which I believe references NSMainNibFile in the plist and actually has the main nib own the app delegate object instance. However Apple's not totally clear on how all that magic works. Nonetheless you can't set the delegate in applicationDidFinishLaunching -- that's a delegate function!
But if you're using a NSMainNibFile and a non-document application, the app delegate is likely being set to an object in your main NIB... in that NIB, the "File's Owner" is also the application delegate class, and the other outlets are non-nil within [NSApp delegate] because it's the main NIB file's owner. From the NSMainNibFile you can create outlets in the App Delegate class, because it's the file's owner.
If you create a second NIB, there are issues accessing the delegate. You don't want to create a object, because that isn't the same object as [NSApp delegate]. You can use the Application placeholder object and bind with a keypath of "application.delegate." But you can't create outlets because the app delegate can't be the file's owner.
But that's irrelevant, because if you have a second NIB that you're creating outlets for, they belong in a custom viewcontroller or windowcontroller subclass that you've declared is that file's owner. Even if that second NIB is loaded immediately, well then the app delegate should instantiate a controller instance to load and own the NIB, if you want outlets, it must be a custom subclass.
Apple sort of breaks this pattern by making the app delegate class the owner of the main menu "window" in MainMenu.xib in non-document applications... but that is because the menu window's a bit special. Anything you do outside of MainMenu.xib is going to need a custom controller class to have outlets.
Additional discussion in this answer about app delegate instances.

Cocoa - awakeFromNib is not called

I have an MainMenu.xib, and AppController is its file owner. I added -(void)awakeFromNib method which worked fine. Now, rounds of fixings down the road awakeFromNib stopped being called, and I can't figure out why. It owns the xib, so it should be called when it is unarchived. What's going on?
EDITED:
Well, I renamed awakeFromNib to something, and called that from init... that worked. Still confused as to why awakeFromNib is not. I also have a +(void) initialize method in there, could that be messing something up?
- (id)init {
self = [super init];
if (self) {
[self something];
}
return self;
}
-(void)something {
NSLog(#"yup");
}
Setting the class name of the File's Owner in the nib is only so you can tell Xcode what object's outlets and actions to show you so you can hook things up. It doesn't affect what object is actually the File's Owner when the app runs and the nib gets loaded.
The MainMenu nib's File's Owner is always the application object, no matter what class name you set for the FO in Xcode's inspector. Setting it to any class name but NSApplication[1] is wrong.
When you run your app, you should find error messages in the Console about any outlets or actions of the AppController that you tried to connect. They couldn't be connected because the application object doesn't have them.
Change the class name back in the nib editor, and create your AppController as a custom object in the MainMenu nib.
Well, I renamed awakeFromNib to something, and called that from init... that worked.
That means that init is getting called, which means you're calling it. That's a valid alternative to creating it in a nib, though you shouldn't override awakeFromNib if it's not in a nib or owning one.
Your choice: Continue creating the AppController using alloc and init, or remove that code and create it in the MainMenu nib instead.
[1]: Or, if you've subclassed NSApplication and changed the principal class of your app bundle to be that subclass, the name of that subclass.

didReceiveMemoryWarning Crash

-Using ARC
-I have 5 separate view controllers all subclassing a class I made called "UIViewControllerWithLoadingView" which subclasses UIViewController.
-In both the subclasses and superclass I allocate and deallocate properties like this:
#property (strong, nonatomic) NSURLConnection *urlConnection;
- (void)viewDidUnload
{
[super viewDidUnload];
self.urlConnection=nil;
}
-Now when didReceiveMemoryWarning is called, the sub classes viewDidUnload method acts fine. BBBUUTTT if I set properties to nil in the super class, UIViewControllerWithLoadingView, the application will crash. Particularly right where I set the properties of the sub class to nil. So for right now I just don't set the properties to nil in the superclass, which becomes problematic because the live bytes just keep piling up at run time.
The rule of thumb is that methods that "clean up"--like dealloc or viewDidUnload--should make the call to super after they do everything else. (And methods that "set up"--like init--call to super first.) I can't tell if that's your problem without seeing all your subclass implementations, but that would be a place to start.
The problem was in the superclass I had a view that extended uiview which had a property reference to the viewcontroller. Well dealloc is automatically called in arc so dealloc would actually set the viewcontroller itself to nil causing a crash. Once I removed the property of the viewcontroller in the custom view class the problem no longer occurred

Trying to set a property value, but it's nil

I declared a protocol in the header file of a Controller that manages a map view.
#protocol UCMapViewDelegate <NSObject>
#required
- (void)pushMapviewRight;
#end
I'm declaring the implementation of the protocol in another view controller (.h) and implement it in the .m file
// in the UCRootViewController.h
#interface UCRootViewController : UIViewController <UCMapviewDelegate>
// in the UCRootViewController.m
- (void)pushMapviewRight
{
NSLog(#"push mapview right");
}
I'm setting the delegate to a property that points to the rootviewController. This is done in the viewDidLoad() of my MapviewController, with a property #property (weak, nonatomic) id<UCMapViewDelegate> delegate;.
// in UCRootViewController
self.mapviewController.rootviewController = self;
// in UCMapViewController
self.delegate = (id<UCMapviewDelegate>)self.rootviewController;
Calling the delegated method. showMenu() gets executed when a button in the mapviewController gets pressed and it works. but the delegate method does NOT get called.
- (void)showMenu
{
NSLog(#"show menu");
[self.delegate pushMapviewRight];
}
But nothing happens.. what is wrong?! Help is greatly appreciated!
I fixed it. At first I used NSLog to verify that self was not nil (which is pretty obvious
, but still) I'm actually not sure why, but self.mapviewController.rootviewController = self; did not "carry over" to the point where I wanted to reference self.rootViewController, although self was not nil at the point where I set it to be the pointer to rootViewController.
I fixed it by creating another initWithRootViewController:(UCRootViewController*) ctrland passed self as an argument when I created the MapViewController.
Can someone explain why the valid reference to self (=rootViewController), was not available in the MapViewController?
Is the rootViewController property a strong reference or a weak one? It should probably be strong. If there are no weak references to the object, then it will be immediately released, and weak references get nilled out when the objects they point to are released. You need a strong reference somewhere in your application for objects to hang around.
As #CodaFi said, your codes look messy. Why do you set delegate property value in UCMapViewController? The delegate should be set in its parent when popup or prepare for the segue.
Basically, if your UCMapViewController has knowledge about UCRootViewController implementing a delegate method, why not call its method from riitVuewController directly? No need to set delegate at all.
Here is one example of using storyboard and segue, UCMyViewController is going to push segue to UCMapViewController:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
...
[segue.destinationViewController setDelegate:self.rootViewController];
...
}

calling super class question

I'm wondering what happens in this case of class hierarchy
MySuperClass : UIViewController
MYSubClass : MySuperClass
MySuperClass lack the method, ViewWillAppear
My question is: if MySubClass has the following method
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
is that code simply ignored (won't be executed) or viewWillAppear in UIViewController will be called?
Just wondering.
It works similarly to normal method calls. When you call on super, the runtime goes up through the chain of superclasses until it finds one that implements the requested method. If it doesn't find one, it will call forwarding methods, and if the method isn't forwarded it will call doesNotRecognizeSelector:. So, yes, viewWillAppear will be called on the UIViewController class.
Say you have:
MySubClass *mySubController = [[MySubClass alloc] initWithNibNamed:nil bundle:nil];
If you do something with mySubController that will cause its view to appear, like push it onto a nav controller's stack, then MySubClass' implementation of -viewWillAppear will be called. As it is now, that implementation just calls super's implementation. Since MySuperClass doesn't override -viewWillAppear, UIViewController's implementation will be called.