I have a controller object that owns an NSMenu and is that menu's delegate, in the interest of lazy population.
However, neither numberOfItemsInMenu: nor menuNeedsUpdate: is ever called, and so the menu remains empty.
I have confirmed that:
The controller object has not been deallocated. (The controller, in turn, owns the menu.)
It does have a menu.
The menu does have a delegate, and that is the controller.
If I implement menuWillOpen:, that is called, but you're not supposed to populate the menu there.
I tried sending the menu an update message, and that had no effect. The delegate remained un-called, and the menu remained empty.
In case it's relevant: This menu is not in the main menu; it is used elsewhere.
Why isn't the menu asking its delegate to populate it? Is there something I've missed, or is this just broken?
Maybe you need a strong reference to the delegate.
Try moving variable declaration out of your method and make a class-level member variable.
look at this answer: https://stackoverflow.com/a/21816149/1664943
Related
I have an NSArrayController bound to CoreData in my application. It is also bound to a TableView that displays the data. Two buttons are bound to the ArrayController that add and remove lines. All of this is working as expected. I can add, edit, save, and remove CoreData Entries.
There is a section of my app that is to accept drag and drop operations from files (working). It takes the data from the files, looks for various information, and is to insert this information into the Core Data database via the NSArray Controller.
I have added the class handling the parsing/adding of the file to the database as an object in IB. I created an IBOutlet for the array controller in the class, and bound the controller to the class' referencing outlet.
If I add a button to the interface to directly call the method that adds a custom record to the database, everything works. If the method is called via the drag and drop operation, nothing works, even logging a simple [arrayController className] returns null (though returns NSArrayController as expected when the method is called from the button click).
The only difference I can see is that when accessed through the button click, the method is called directly, while the other way passes through my drag and drop class before loading the parsing class, but I'm completely stuck on how to remedy this situation. I'll be happy to provide code, just not sure which code you'll need.
Any help is appreciated. Thanks!
==================
UPDATE
turns out I was connecting the IBOutlet to a class (a subclass of a view) object in IB instead of to the view itself handling the drops. Connecting these up made things work. Well, not work, I have other issues to iron out now, but the Array controller is now instantiated.
Moved from comment to answer: The array controller you are trying to add stuff is not instantiated. I assume you are not referring to your original NSArrayControllerinstance but maybe a new created one? Probably a problem of communication between your class instances.
Debugging this should be straightforward ... using the debugger. Set a few breakpoints (one at each action the button(s) call, and one at each point where your class instances are meant to talk to each other (your importer and your main controller)). Run, test, step through the code when the debugger breaks at each breakpoint.
My guess: An outlet is not hooked up (is nil) in IB or is not yet reconnected at runtime (see -awakeFromNib and make sure you're not trying to touch an outlet or action that hasn't been fully reconnected from the nib at runtime by the time you're trying to use it).
Something’s not hooked up right, BUT you don’t want to do it this way anyways. There’s no advantage to inserting via an NSArrayController. Just create new objects with NSEntityDescriptions:
+ (id)insertNewObjectForEntityForName:(NSString *)entityName inManagedObjectContext:(NSManagedObjectContext *)context;
And you’re done. If your NSArrayController is hooked up correctly it’ll auto-fetch the new objects at the end of the event so the user will see them “immediately.”
I'm finding that with a toolbar defined in a nib, the toolbar delegate's toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar: method doesn't get called. So how can I tell if one of my custom items is going into the customization palette? The docs say that in the nib case I can still use that method to "augment functionality", but I'm not getting any augmenting.
Update: I tried implementing that method in a subclass rather than the delegate. It does get called, and only when setting up the customize sheet, but strangely toolbar and itemIdentifier are nil for all items.
Update 2: I'm getting around this by overriding viewWillMoveToWindow: in my custom view, and checking whether the new window has a toolbar. I'm seeing the views get moved back and forth between toolbarless and toolbarred winodows, which suggests that this may actually be a better solution than a delegate method that only gets called when the item is created.
I need to get notified when menu items in an NSMenu instance get removed. Specifically because I'm holding a NSMenuItem *selectedItem instance in my class. If this selectedItem gets removed from my NSMenu instance, i want to set the selectedItem to nil;
There is a notification for NSMenu called "NSMenuDidRemoveItemNotification" that works when you remove individual items from the menu. But when you call [myNSMenu removeAllItems] it does not get called.
Any ideas? , Do I need to subclass NSMenu ?
Thanks.
Yes, you are right, there is no notification for removeAll.
And you rightly said you need to subclass
Or, need some tricks (may be hacky work)
Even you can make a category with a method as removeEachItem.
If the menu is left with only one item you can track that NSMenuDidRemoveItemNotification is getting called last time, you are done with your requirement.
I have a menu item whose state should depend on whichever NSDocument is open. From my understanding, to make its state change dynamically I should use the NSMenu delegate method menuNeedsUpdate:.
It seems like I would want to have the menu's delegate be the First Responder in MainMenu.xib. However, Interface Builder won't let me set it as the Main Menu's delegate. How can I make a delegate which will be able to access the currently active document?
I generally make such changes in the validateMenuItem: method being called before the menu is shown. The receiver of the action is asked whether the item is to be enabled or not. But you can do pretty much any change there. Since 10.5 it is also safe to add and remove items during such a call.
I have a document based cocoa application with an item in the application menu hooked up to an IBAction. Clicking the item needs to perform a task that uses an IBOutlet in the main nib file which is using another class, MyDocument. Creating 2 objects of the same class, one in each nib seems to not be working. How can I access the outlet?
Actions for menu items are often sent to the first responder so that whatever is currently selected can act on it.
It sounds like this action is something that works on the current document, then it should be implemented by the document. In this case have the menu send it's action to the first responder and then put the action method in the MyDocument class.
If the action you are trying to send is a custom one: in the Main Menu nib select the First Responder item, add your method name, then connect the menu item's selector to the action.
Read the Responders section of the Cocoa Event-Handling Guide for more info.
To summarize the above, in your NIB/XIB file, in interface builder make the connection to the First Responder object, not to Files Owner or anything else. You'll still be offered a lit of actions across potential first responders.
Cocoa then takes that selector and looks for it, starting with the NSView (if any) that's currently the first responder, then with the NSDocument that's currently in use, then with it's window controller etc etc all the way up to the Application delegate. The first object it checks that actually implements that method, it will use that object (after validating it with that same object).
So:
#interface MyDocumentTypeA : NSDocument {
}
-(void)myMenuAction:(id)sender;
-
#interface MyDocumntTypeB : NSDocument {
}
// -myMenuAction: not implemented here
-
#interface MyApplicationDelegate ... {
}
-(void)myMenuAction:(id)sender;
-
In Interface builder (or even programmatically), if you've linked the "action" of the menu item to a selector named "myMenuAction:" on the First Responder (which equates to not specifying a target when done programmatically), for the above two document subclasses the following will happen.
For MyDocumentTypeA, when the user selects that menu item, MyDocumentTypeA's -myMenuAction: will be invoked. Since MyDocumentTypeB does not implement this action, Cocoa will continue to look up the responder chain until it gets to your application delegate, which does implement it, so it will be invoked here instead.
If Cocoa finds no objects in the responder chain that implement the method, the menu item remains disabled.
There is a way how to do this, I've posted the answer in a similar thread: Access IBOutlet from other class (ObjC)