NSMenu delegate does not trigger menuWillOpen - objective-c

I've got an Interface Builder NSMenu-Object. I added my custom Class "StatusBarMenu".
The StatusBarMenu.h file looks like this:
#interface StatusBarMenu : NSMenu <NSMenuDelegate>
The StatusBarMenu.c file looks like this:
- (void)menuWillOpen:(NSMenu *)menu {
`NSLog(#"open");`
}
The Menu is assigned in the AppDelegate.c as follows:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.statusBar = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
self.statusBar.highlightMode = YES;
[self.statusBar setMenu:self.statusMenu];
}
And the AppDelegate.h:
#import <Cocoa/Cocoa.h>
#import "StatusBarMenu.h"
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (strong, nonatomic) NSStatusItem *statusBar;
#property (weak) IBOutlet StatusBarMenu *statusMenu;
The Menu opens, but menuWillOpen is not called.
Did i miss anything?
I appreciate any help!
Thanks.

You have to set the delegate, either in Interface Builder by a connection (statusMenu > delegate to AppDelegate) or in code in applicationDidFinishLaunching
self.statusMenu.delegate = self;

Related

"missing setter or instance variable" log message occurs initializing NSWindowController with Objective-C in Xcode:

Here is an abstract I took from an app that already works in which a parent window and sheet are processed. The abstract here compiles, launches, and displays the parent window without having received the message I sent to its text field. The run produces 'missing setter or instance variable' log messages for the text field, the button, and the window itself. For some reason I have not gotten the parent window to be properly initialized, and I suspect I will have the same problem with the sheet window but I can't get past this problem to debug the rest of the app.
I believe I have omitted something fundamental in the process of connecting the window to its File's Owner, even though when looking at the connections inspector for the .xib it shows the custom class to be the ParentClass and the various connections are made. I can find no instructions in Apple's labyrinthine documentation nor here in StackOverflow to guide me through the connection process that would allow me to discover the part(s) I'm missing.
Anything you can offer will be gratefully studied.
ParentDelegate.h
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#class ParentClass;
#interface ParentDelegate : NSObject <NSApplicationDelegate>
#property (assign) IBOutlet NSWindow * window;
#property (weak, nonatomic) ParentClass * parentController;
#end
ParentDelegate.m
#import "ParentDelegate.h"
#implementation ParentDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { }
- (void)applicationDidBecomeActive:(NSNotification *)aNotification { }
- (void)applicationDidResignActive:(NSNotification *)aNotification { }
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
{ return YES; }
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{ return NSTerminateNow; }
#end
ParentClass.h
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#interface ParentClass : NSWindowController {
}
#property (assign) IBOutlet NSWindow * window;
#property IBOutlet NSTextField * messageTextField;
#property IBOutlet NSButton * proceedButton;
#property (strong) NSMutableString * parentPropInfo;
- (IBAction) awakeFromNib;
- (IBAction) doProceed:(id)sender;
#end
ParentClass.m
#import "ParentClass.h"
#import "ParentDelegate.h"
#import "SheetClass.h"
#implementation ParentClass
ParentDelegate * parentDelegate;
SheetClass * sheetController;
- (IBAction)awakeFromNib {
parentDelegate = [NSApplication sharedApplication].delegate;
parentDelegate.parentController = self;
sheetController = [[SheetClass alloc] initWithWindowNibName: #"SheetClass"];
_messageTextField.stringValue = #"Click Proceed button";
}
- (IBAction)doProceed:(id)sender {
_parentPropInfo = #"Hello!".mutableCopy;
[NSApp runModalForWindow:sheetController.window];
// Sheet active now until it issues endModal, then:
_messageTextField.stringValue = sheetController.sheetPropInfo;
[NSApp endSheet: sheetController.window];
[sheetController.window orderOut:self];
}
#end
SheetClass.h
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#interface SheetClass : NSWindowController {
}
#property (assign) IBOutlet NSWindow * window;
#property (weak) IBOutlet NSTextField * propTextField;
#property (weak) IBOutlet NSButton * returnButton;
#property (strong) NSMutableString * sheetPropInfo;
- (IBAction)awakeFromNib;
- (IBAction)doReturn:(id)sender;
#end
SheetClass.m
#import "SheetClass.h"
#import "ParentClass.h"
#implementation SheetClass
ParentClass * parent;
- (IBAction)awakeFromNib {
parent.window = self.window.sheetParent;
_propTextField.stringValue = parent.parentPropInfo;
}
- (IBAction)doReturn:(id)sender {
_sheetPropInfo = #"Done!".mutableCopy;
[NSApp stopModal];
}
#end
Ultimately I would like to use this mini-app as a starting template for several other apps.

NSButton IBAction Crash unrecognized selector

Running into a simple problem and not quite sure what is causing it. Linked a NSButton up to a ViewController xib. The property is referenced and then I linked up the IBAction to the view controllers view. I'm getting a crash whenever I press the button with an unrecognized selector message. I know I'm doing something wrong but on iOS this is pretty standard.
Here is the code:
#import "AppDelegate.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
IPVLocationViewController *mainViewController = [[IPVLocationViewController alloc]initWithNibName:#"IPVLocationViewController" bundle:nil];
self.window.contentView = mainViewController.view;
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
#end
#import "MainViewController.h"
#interface MainViewController ()
#property (weak) IBOutlet NSButton *mainButton;
#end
#implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do view setup here.
}
- (IBAction)mainClick:(id)sender {
NSLog(#"THE BUTTON WAS CLICKED");
}
#end
In your Nib , it looks like your view controller instance is of type NSViewController instead of MainViewController.
So select the view controller in your Nib (or storyboard), and change its type to MainViewController.
Of course, if this view controller isn't being loaded from a nib or storyboard, then just check where you create it and make sure you created an instance of the correct class.
Solved it:
The accepted answer in this post helped me:
Needed to hold a reference to the view controller in the AppDelegate.
#interface AppDelegate ()
#property (nonatomic, strong) MainViewController *mainViewController;
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
self.mainViewController = [[MainViewController alloc]initWithNibName:#"MainViewController" bundle:nil];
self.window.contentView = self.mainViewController.view;
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
#end

Error when using NSWindowController

I just started a new Cocoa project after a long time... And I don't know why, but I always get an error when calling a xib by a NSWindowController. What I do is really very simple: I have a new project as a starting point and then I don't wantz to call the xib from Appdelegate, but from a subclass of NSWindowController. Then the output tells me that:
2014-11-12 09:58:18.519 SimpleTest[8554:378690] ApplePersistence=NO
2014-11-12 09:58:18.671 SimpleTest[8554:378690] Failed to connect (window) outlet from (NSApplication) to (NSWindow): missing setter or instance variable
Okay, how does it look in code? My Appdelegate looks like this:
#import "AppDelegate.h"
#import "MainWindowController.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#property (strong) MainWindowController *mainWindowController;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
_mainWindowController = [[MainWindowController alloc] initWithWindowNibName:#"MainMenu"];
[self.mainWindowController showWindow:self];
}
#end
Nothing special so far. The MainWindowController looks like this:
#import "MainWindowController.h"
#interface MainWindowController ()
#property (weak) IBOutlet NSWindow *window;
#end
#implementation MainWindowController
- (id)initWithWindow:(NSWindow *)window
{
self = [super initWithWindow:window];
if (self != nil)
{
//do something
}
return self;
}
#end
And again very simple... Additiponally I have some modifications in IB: File'Owner of MainMenu.xib becomes MainWindowController. Its 'window' outlet is connected to the Window of the application. The delegate of Window is connected to File's Owner. Well, that's it! But why do I receive this error? What am I doing wrong?
---EDIT---
this shows the connections in IB
The most important is using right selector to create new instance and having all wired up correctly.
Steps:
1. Add new xib with window or an empty one and add window to it
2.Select File owner and set it to NSWindowController or its subclass.
Select window and connect it to File owner
Make new NSWindowController instance
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSWindowController *windowController = [[NSWindowController alloc] initWithWindowNibName:#"Window"];
[NSApp runModalForWindow:[windowController window]];
}

EXEC_BAD_ACCESS when clicking on a button in objective C

I am just learning and trying to put forth some of the knowledge with objective c and cocoa. I have a little program that has a login screen which then displays a main menu. On the main menu view, there is a button that should load a view to be able to add some data to the app. When I click on the button, it doesn't fire the IBAction but throws an error
EXC_BAD_ACCESS [StartMenuViewController performSelector:withObject:]: message sent to deallocated instance 0x6080195e9f90
I know that it is because there is an object that is not instantiated when the message is being sent, but I cannot find out why. Sorry for the code and the novice level here is the main menu view controller StartMenuViewController.m file:
#import "StartMenuViewController.h"
#import "AppDelegate.h"
#import "MasterViewController.h"
#interface StartMenuViewController ()
#end
#implementation StartMenuViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do view setup here.
}
-(IBAction)showStrainView:(id)sender{
AppDelegate *delegate = nil;
delegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
MasterViewController *addStrainView = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
[delegate swapView:self.view toView:addStrainView.view];
}
#end
here is the StartMenuViewController.h
#import <Cocoa/Cocoa.h>
#interface StartMenuViewController : NSViewController
#property (weak) IBOutlet NSButton *showStrainViewButton;
#end
Here is the AppDelegate.h
#import <Cocoa/Cocoa.h>
#class loginView, MasterViewController,StartMenuViewController;
#interface AppDelegate : NSObject <NSApplicationDelegate>{
loginView *loginView;
MasterViewController *masterViewController;
}
#property (assign) IBOutlet NSWindow *window;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (strong) loginView *loginView;
#property (strong) MasterViewController *masterViewController;
#property (strong) StartMenuViewController *starMenuViewController;
-(void)swapView:(NSView *)view1 toView:(NSView *)view2;
#end
Here is the AppDelegate.m
#import "AppDelegate.h"
#include "MasterViewController.h"
#import "ScaryBugDoc.h"
#import "Strains.h"
#import "loginView.h"
#interface AppDelegate()
#end
#implementation AppDelegate
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
#synthesize loginView;
#synthesize masterViewController;
#synthesize starMenuViewController;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// 1. Create the master View Controller
self.loginView = [[loginView alloc] initWithNibName:#"loginView" bundle:nil];
// 2. Add the view controller to the Window's content view
[self.window.contentView addSubview:self.loginView.view];
self.loginView.view.frame = ((NSView*)self.window.contentView).bounds;
}
-(void)swapView:(NSView *)view1 toView:(NSView *)view2{
//[view1 removeFromSuperview];
[self.window.contentView addSubview:view2];
view2.frame = ((NSView*)self.window.contentView).bounds;
}
#end
If you need the loginView.h and loginView.m files I can add them as well. I would appreciate any and all help. Thanks in advance
The problem is here:
MasterViewController *addStrainView = [[MasterViewController alloc]initWithNibName:#"MasterViewController" bundle:nil];
[delegate swapView:self.view toView:addStrainView.view];
You don't keep a reference to the MasterViewController so it gets deallocated even though its view is kept around. Now anytime the view tries to access methods from the view controller, things fail.
You should make addStrainView a child view controller of self in the above code so the view controller sticks around as long as its view.

How to access view controller variables from the app delegate... and vice versa?

I would like the view controller to be able to access dog in the app delegate.
I would like the app delegate to be able to access mouse in the view controller.
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
{
int mouse; // <----------------
}
#end
- (void)viewDidLoad
{
[super viewDidLoad];
mouse = 12; // <-------------------
NSLog(#"viewDidLoad %d", dog); // <---------------
}
#import <UIKit/UIKit.h>
#class ViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
int dog; // <---------------
}
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) ViewController *viewController;
#end
- (void)applicationWillResignActive:(UIApplication *)application
{
NSLog(#"applicationWillResignActive %d", mouse); // <--------------
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
dog = 77; // <---------------------
NSLog(#"applicationDidBecomeActive");
}
Part 1:
In the ViewController.h:
-(int)mouse; //add this before the #end
In the ViewController.m, add this method:
-(int)mouse
{
return mouse;
}
To access mouse from AppDelegate, use self.viewController.mouse
For example;
NSLog(#"ViewController mouse: %i", self.viewController.mouse);
Part2:
In the AppDelegate.h:
-(int)dog; //add this before the #end
In the AppDelegate.m, add this method:
-(int)dog
{
return dog;
}
In the ViewController.m:
#import "AppDelegate.h"
To access dog from ViewController, use this:
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"dog from AppDelegate: %i", [appDelegate dog]); //etc.
In your view controller header file add mouse as a property:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
{
NSInteger mouse; // <----------------
}
#property (nonatomic, assign) NSInteger mouse;
#end
Synthesize the property in your view controller implementation just below the #implementation line:
#synthesize mouse;
In your app delegate add dog as a property:
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
NSInteger dog; // <---------------
}
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) ViewController *viewController;
#property (nonatomic, assign) NSInteger dog;
#end
Also synthesize dog in your app delegate implementation.
Now in your app delegate, assuming you have a reference to your view controller, you can access mouse like this:
viewController.mouse = 13;
You can do the same thing with your app delegate class, which can be accessed from any view controller using (assuming the name of your app delegate class is AppDelegate):
((AppDelegate *)([UIApplication sharedApplication].delegate)).dog = 13;
I would recommend that you use also use NSInteger instead of int.