3

In my Cocoa app I have two NIB/XIB files that I need to connect:

  1. MainMenu.xib: contains a custom object for the NSApplication delegate object and connects it to the proper outlet in the NSApplication placeholder.

  2. ContextMenu.xib: sets up an NSMenu; one entry is supposed to open the preferences dialog

My custom app delegate defines an IBAction to bring up the Preferences window for my app.

How can I connect the NSMenuItem (second NIB) for showing the preferences to the action defined in the application delegate (first NIB)?

The Docs say this is supposed to be easy, but they fail to mention how exactly to do this in Interface Builder:

If the menu item refers to an application-level command, you can implement that command directly in the application delegate or just have the delegate forward the message to the appropriate object elsewhere in your application.

I somehow need to access the app delegate in the second NIB, tell Interface Builder that it is of my custom class (so it knows about the custom IBAction), and connect it to the action of the menu item.

Thanks for any pointers!

Mark
  • 6,647
  • 1
  • 45
  • 88
  • Found somewhat of a solution with the detour of an action in the File's owner that then calls out to the app delegate. Is there a way to avoid this? http://www.iphonedevsdk.com/forum/iphone-sdk-development/46663-accessing-ibaction-declared-app-delegate-interface-builder.html – Mark Sep 13 '11 at 07:24

4 Answers4

3

If the other objects are in the responder chain, then you can just hook the action up to the first responder.

Notice the "if", though.

As Maurice Kelly mentions, your App Delegate is already part of the responder chain, so you can use that: Define a custom action on the First Responder (in Interface Builder) and a corresponding action on your App Delegate. If you have many actions that could clutter up the App Delegate, though, so you might want to use this architecture only for simple apps.

Monolo
  • 18,205
  • 17
  • 69
  • 103
1

For bindings in the second NIB, application delegate bindings can be accessed by binding to Application with a model key path starting with delegate. ie delegate.managedObjectContext

A warning: Do not create an app delegate object in the second NIB. If you do, you will end up with a second app delegate instance with a second, separate managedObjectContext. The NIB creates another app delegate object. This is terrible.

In the loading of MainMenu.xib, [NSApplication sharedApplication] gets its delegate set to the delegate object instantiated in MainMenu.xib. If you create a delegate object in another NIB, you will have a delegate object that doesn't match [NSApp delegate]. (And you will smash your head into the wall trying to discover why the view of the context doesn't update)

stevesliva
  • 5,351
  • 1
  • 16
  • 39
0

I got the same problem, and solved it like this:

  • I created only one menu (MainMenu.xib). Since menu items for which the first responder does not provide any action are automatically greyed out, the items that are meant for the Document window will be greyed out when the Prefs window is activated.

  • I created a PrefsWin.xib for the definition of the prefs window. The File's Owner of that xib is a class named PrefsWinController, which inherits from NSWindowController.

  • The actions in MainMenu.xib simply connect to the First Responder rather than the delegate. If your instance of <NSApplicationDelegate> is an instance of NSResponder, the delegate will automatically act as the last responder in the chain. (I don't know where this might be documented, but it certainly works in my project.)

digory doo
  • 1,978
  • 2
  • 23
  • 37
  • App delegate behave like a responder, even it's not inherit from NSResponder, you can find Apple documents at Event Architecture, for section Responder Chain for Action Messages. – reviver Sep 03 '16 at 03:13
0

Your second NIB will have a File's Owner which you should set to a class that is instantiated by your application. Within this class you can create a reference to the App Delegate which can be filled in when the class is being instantiated (e.g. using setAppDelegate:self if you are creating it from within the delegate).

Create an IBAction in this class which simply passes the action on to the App Delegate:

- (IBAction) passItOnAction:(id)sender {
    [appDelegate openPreferences:sender];
}
Maurice Kelly
  • 1,462
  • 12
  • 15
  • Oops - just saw your edit. I'm not sure if there is an alternative to the File's Owner action detour. The File's owner is a proxy object by which your NIB can communicate with objects created outside of it's little world. – Maurice Kelly Sep 13 '11 at 08:21
  • I was hoping to avoid the detour/passItOn style (that's what I have at the moment). Is there a way to add the app delegate as a proxy object or sorts? – Mark Sep 13 '11 at 09:23
  • Hmmm, I don't think you can add more proxy objects. However, I guess you could make the App Delegate the File's Owner for your second NIB. I'm not sure what the repercussions of that would be. – Maurice Kelly Sep 13 '11 at 09:49
  • I don't have the reputation to comment above, but @Monolo's answer seems pretty good. Your App Delegate should be part of the `Responder Chain` and so defining a custom action on the `First Responder` and a corresponding action on your App Delegate should work. I've tried it on a sample project (non Document-based) and it worked for me. – Maurice Kelly Sep 13 '11 at 10:31
  • Ok, I added more details based on your comment to Monolo's answer. Thanks! – Mark Sep 13 '11 at 12:38