What are the correct connections for App Delegate and Application - objective-c

Unannounced, the 2 notices in the image below were discovered while searching for why -applicationShouldTerminate: is not being called in AppDelegate.m on quit (Cmd+Q). It worked some time ago.
Hovering over the two yellow triangles reveals:
NSObject does not have an outlet named delegate.
The action 'terminate:' is not defined on 'NSObject'.
Xcode is not showing errors or warnings and the app builds.
-applicationShouldTerminateAfterLastWindowClosed: IS called within AppDelegate.m when the red dot of the window is clicked.
My experience with Cocoa is thin (learning). I've compared the connections for File's Owner, Application and App Delegate in 2 other projects, and think a missing window outlet might be the cause. The notices above point to something else.
I would like to make sure the connections are correct as a first step. How do I repair this?
Edit: Add image of Main Window Controller connections
Edit 2: Add image of File's Owner connections

In the main NIB of an application, the two placeholders, File's Owner and Application, both end up referring to the same object. That object is the application object, the sole instance of NSApplication or a custom subclass of it. The Application placeholder is always holding the place of the application object because that's its purpose. The File's Owner placeholder is holding the place of whatever object is specified as the NIB's owner when it is loaded at run time. When Cocoa loads the main NIB at application startup, it specifies the application object as the owner. For other NIBs, File's Owner will likely be some other object.
However, Interface Builder doesn't know that a given NIB is the main one. So, it treats those two placeholders independently.
I don't know why Interface Builder has taken to setting the class of the Application placeholder to NSObject. It should really be NSApplication. That's why Interface Builder doesn't realize that the application object has a delegate outlet and an action method -terminate:.
As it happens, the class of File's Owner is properly set to NSApplication.
So, there are two ways to fix this:
Set the class of the Application placeholder to NSApplication or, in the rare case that you're using a subclass, that subclass.
Disconnect those connection from the Application placeholder and connect them to File's Owner instead. This is the way that the standard project templates do it.
For any given main NIB, you should probably standardize on using one or the other but not both. That is, one or the other should have no connections. That way you avoid conflicting or redundant connections.

Related

Using separate .nibs and getting logic out of App Delegate

I have a document based app using the standard template. I have two auxiliary panels in Main Menu.xib, and my main logic is currently in the App Delegate, mainly through an IBAction in App Delegate triggered by a button on one of my panels. Everything works fine, but I know it should be organised better.
I have implemented a Preferences panel as suggested by Hillegass in Chapter 12. So:
Create a custom controller called AppController containing instance
of PreferenceController. This is instantiated in Main Menu.xib
Custom PreferenceController class which is subclass of
NSWindowController. This loads the Preferences.xib
Preferences panel created in Preferences.xib
Before I get too far in the app’s development, I want to be sure I’m organising things the right way.
I want to move my main logic out of App Delegate, possibly into App Controller. I want App Controller to be in charge of showing and hiding the various panels, and I want each panel to have its own .xib.
I have created two more subclasses of NSWindowController and made them ivars of the AppController, alongside the PreferencesController eg. Panel1Controller & Panel2Controller.
My problem is that interface builder is not letting me connect an IBAction in AppController to a button on one of my panels. It only lets me connect to the .xib file’s owner, i.e. Panel1Controller in the case of Panel1.xib.
If I put the logic in Panel1Controller, how do I get at one of the other panels (say Panel2Controller?) in order to hide it?
Am I going about this the right way?
Getting very confused….
Any help much appreciated!
Regards,
John
Just for simplicity sake I'd move all the nib elements controlled by the NSWindowController sub-classes out of the main nib and into nibs with the same name as the (NSWindowController) sub-classes that control them. DON'T expose IBOutlets or IBActions in the sub-class headers (they should be in a class extension ("#interface MyWindowController ()") in the source file for that sub-class.
Also, is the AppController a 2nd app delegate? Probably not what you want (there can only be one); you should merge its logic into the existing app delegate if that's the case.
I just came across this method.
This seems to do away with NSWindowController altogether, and make the AppController the file's owner of both .xibs. This way IB allows you to create outlets in AppController for each window, and contain actions.
I have created a very simple, two-window app using this method that hides one window when a button on the other is pressed. Before I go away and re-organise my main app, I want to be sure I'm doing this the correct, standard way, if there is one?
This page contradicts this method, by saying one window = one .xib + one NSWindowController subclass.
If you do it the latter way, how can one window talk to another, when you can't create outlets/actions in the AppController? Actions implemented in a window's NSWindowController class can't see outlets of another window, so how can they communicate?
This seems like pretty standard, basic stuff and yet I cannot find any sources which say which way is correct/best practice.
Another method I have read about here mentions using Notifications.
I'm still wondering though - which is the most common "accepted" method of loading two or more windows in separate .nibs and getting them to talk to each other? I'm surprise this info has been so hard to find.
If you're going to follow this pattern, separate AppDelegate and AppController, then your MainMenu.xib should not contain any window objects of any kind...it should just contain the application menu. Each additional window (NSWindow/NSPanel, etc.) gets its own .xib and its own NSWindowController.
There are two ways to assign references to your properties (IBOutlets) and methods (IBActions): 1) programatically, 2) via Interface Builder. Let's cover the second method!
To be able to wire things up from Interface Builder (IB) you will need a reference to the target object inside IB. For the MainMenu.xib file, this gets setup automatically: the MainMenu.xib contains an "AppDelegate" Object reference. The Object reference exposes the properties and methods in the AppDelegate class that are prefixed by the "IBAction" and "IBOutlet" macros. I write Object (with a capital O) because it is a widget available in the "Object Library" in IB.
You can easily create an instance of a custom objects inside a .xib file (via IB) by dragging an "Object" widget from the Object Library into your .xib. Then set the Object's class to that of your custom class. Once you've done this, the IBActions and IBOutlets in your custom class object will be available in IB. [Note: one thing to remember when doing this, is that when you load the xib, the object will be instantiated automatically. No need to alloc and init from within AppDelegate...you still have to call showWindow: on it].
As you mentioned, another approach is to simply have all of your additional .xib files owned by the AppController. That would be convenient, but it also gets 100% away from the architecture that you were trying to follow in the first place. In other words, if you're going to follow that style, why not just skip the separate AppDelegate and AppController in the first place, and just stick with the former (which would then be a Controller and Delegate).

cocoa could not connect action

I've been fiddling with Objective-C + Cocoa and writing a fairly simple Cocoa application. Then I encountered a runtime error that has no effect on my program execution:
Could not connect the action textField: to target of class BarController
I'm experimenting with pulling some of the windows out of MainMenu.xib and loading them with separate controllers and xib files.
In one window within a new xib I've created a Text Field and linked it to an IBOutlet NSTextField (textField) in a new NSWindowController subclass. It works and I am able to use textField to update the contents of the Text Field.
I am curious why I am getting the above runtime error and I'm hoping that understanding it will clear up some of the magic around the UI construction process.
Not much magic with plain IBOutlets, really - the fun starts when using Bindings or actions sent to some yet unknown target via First Responder and the responder chain :-)
Regarding your error:
Sounds like you've connected an outlet to a target that doesn't exist in your target class?
You might have established a connection to a property in File Owner (or some other proxy object) at some point where the owner's class was e.g. MyAppDelegate.
Then you've moved the window (or other object containing the outlet) to some other .xib and now the owner's class is MyWindowController that doesn't have a property of the same name you've connected your outlet to - and voila, the runtime won't be able to establish the connection for your outlet at runtime.
Just double-check your outlets in the Interface Editor, there's probably already some kind of warning message displayed next to outlets that look fishy.
Delete or reassign them and you're done.

What is the need of File's owner in xcode xib files? Can i do the same things without file's owner?

Why should I set File's Owner's Class Identity rather than the Class Identity of my custom object that is shown in the nib and make the connections from it? What happens if I set file's owner to nil?
To me everything works fine with nil file's owner so what is the deference in doing the connection from it?
A NIB represents an archived object graph. You can load it and that object graph will be reconstituted. The thing, you usually want/need the newly-loaded object graph to be hooked into the already-existing object graph of your program. You don't want it to be standing apart, disconnected from everything else.
There are a few ways that the newly-loaded object graph can get connected to the rest of the program's object graph. One way is the set of proxy objects available in a NIB. There's one for the application object. Another such proxy object is File's Owner. A proxy object is a thing which has a representation in the NIB but is not actually contained in the NIB. Unlike the other objects in the NIB, the objects represented by the proxies are not created when the NIB is loaded, they exist before the NIB is loaded. The proxies allow connections between these pre-existing objects and the objects in the NIB. That's how the new object graph from the NIB can be connected to the existing object graph of your program.
The MainMenu NIB is unusual. It is automatically loaded at application startup by Cocoa, which means there isn't (can't be, really) much in the way of pre-existing objects. That NIB also usually contains an instance of the app delegate, which is a kind of coordinating controller. Usually, though, other types of NIBs would not contain coordinating controllers. (They do contain mediating controllers, like NSArrayController, but that's different.) Rather, coordinating controllers are typically created in code and, often, they are responsible for loading NIBs.
For example, you would use an NSWindowController as the coordinating controller for a window. The window would be defined in a NIB. The window controller would be instantiated in code – whichever code decides that a window should be created – and it would load the NIB. It would be the File's Owner of the NIB, too. It would manage the window and the top-level objects of the NIB.
If you are setting the File's Owner to nil, then a) you probably are dealing with very simple NIBs at this point, and b) you may be leaking top-level objects from the NIBs that you load.
File's owner is the file that contains all the IBOutlets and IBActions for that view. For example, if you have a class "ViewController" and it contains an IBOutlet UIButton *button and -(IBAction)changeViewWhenButtonPressed: (id) sender, the only way you can connect the outlet and action is through setting "ViewController" as your view's File's Owner.
I am relatively certain that Class Identity is synonymous with File's Owner.
Also, these links might be helpful:
What are File Owner and First Responder in iPhone SDK - xCode?
File's Owner Definitions
What is File's Owner
The “file's owner” is the way that objects in the nib can refer to objects outside the nib, and vise versa. (There are also some more complex ways to do that, but they're not used as often.) If you don't need to do that, you don't need to use file's owner.
For the main app, the file's owner is the Application object. You might not have a need to make connections to it, if all your application logic is in a custom class also instantiated in the nib and if you use “first responder” for action messages sent to the application. This is OK.
If you have a document window or popover or something, frequently the file's owner is the object being viewed, and so it's useful to be able to attach ui to it. You might load the same nib many times, each 'owned' by a different instance of that class — a different document or inspected-object or something.
(Fundamentally, the file's owner is just whatever object was passed to the "owner:" parameter in the nib-loading method.)

What is the job of an Object I am binding to?

When I use Interface Builder > Inspector > Bindings to set up an binding for one of my view Items (i.e. an textfield), then I have to specify an object to which this view item will be bound to.
So I am wondering now, what exactly is the job of this object I specify in "Bind to:"?
I assume that Interface Builder automatically creates some methods which do all that synchronization stuff. Is that right?
And what does it mean when I "Bind to: File's Owner"? Is that my file with the main-Method inside?
… what exactly is the job of this object I specify in "Bind to:"?
You bind your view to your controller. The controller owns the model; the controller key you bind to is the name of a property that serves up some part of that model. The model objects have their own properties, and you may (in some cases must) provide a model key path along with the controller key.
I assume that Interface Builder automatically creates some methods which do all that synchronization stuff. Is that right?
Nope. IB never ever creates methods. The Bindings system does all that synchronization stuff, and it already exists. IB just calls it (specifically, it calls the bind:::: method I mentioned in my answer to your other question).
And what does it mean when I "Bind to: File's Owner"?
The File's Owner is the object that owns all the top-level objects in the nib file. The owner of the MainMenu nib is the application object (NSApp). In a document-based application, the document object will load a nib containing the document window; as such, it is the owner of the window, along with any other top-level objects in that nib.
Is that my file with the main-Method inside?
There's no such file, because there's no such method. There is a main function, but it's a function, not a method of an object. There's no object there, so you can't bind to it.
And you can't bind to a file, only an object. The source files disappear* when you link the program into a single executable. The executable contains only classes and functions, and the nibs contain objects (instances of the classes).
If you're asking which file is being owned, it's the nib file (or, more precisely, its contents—but “File's Contents' Owner” is a bit long).
*Well, except for debug symbols, which identify the filename and line number of each instruction.
The object you bind to has to be key value coding and key value observing compatible. Bindings is just a wrapper that use both those technics in a way that results in much less code.
If you really want to know how it works, there's an entry in Mike Ash's blog how KVO works..
I don't know if you want that much details. I suggest that you read the intro to bindings of cocoadevcentral.com. It makes a fairly good job at explaining them.
To your specific question about the File's Owner, Apple writes:
Each Cocoa application has a main nib
file that contains the
application-specific menus and
possibly one or more windows. NSApp
is File's Owner of the main nib
file. When an application launches,
NSApp loads the main nib file,
unarchiving it, and displays the menus
and initial windows.

Connecting delegate classes in Objective-C

I've got two controls in my Interface Builder file, and each of those controls I've created a separate delegate class for in code (Control1Delegate and Control2Delegate). I created two "Objects" in interface builder, made them of that type, and connected the controls to them as delegates. The delegates work just fine. My problem is, I need to share information from one delegate to the other delegate, and I'm not sure how.
What is the best way to do this? Combine the two delegates into one class, or somehow access a third class that they can both read? Since I'm not actually initializing the class anywhere in my code, I'm not sure how to get a reference to the actual instance of it (if there is an actual instance of it), or even access the "main" class that the project came with.
You can add outlets from either delegate to the other delegate. There are two ways to add an outlet to an object in IB (assuming you're using Xcode/IB version 3.0 or later:
If you have not generated the code for your delegate classes yet, select the desired delegate, then open the "Object Identity" tab in the IB inspector. Add a "Class outlet" of type NSObject. You should then be able to set this new outlet to the other delegate. Of course you will have to generate the code for your delegate class and add the generated source files to your Xcode project before you can load the nib.
If you've already generated the code for the delegate class (or added an NSObject to your NIB and set its Class to an existing class in your Xcode project), add an instance variable to the delegate class:
IBOutlet id outletToOtherDelegate;
As long as your Xcode project is open (as indicated by the green bubble in the lower-left of your NIB window), IB will automatically detect the new outlet and allow you to assign it to the other delegate object in your NIB.
Cocoa automatically connects these outlets at NIB load time. Once awakeFromNib is called on instances of your delegate objects, you may assume that all the other objects in the NIB have been instantiated and all outlets have been connected. You should not assume an order on calls to awakeFromNib, however.
I think you can create outlets on each one and cross-bind them so that they each have the same data all the time. If there's one model object they need to share, that's pretty tidy. I don't actually know how to do this; I think I saw it in an iPhone tutorial one time!
I don't have my Mac in front of me currently since I'm at work, but would it be possible to bind an instance of one delegate to a member of the other delegate? This would be similar to binding an NSArrayController to a member of another controller class, for example.
However, depending on what the delegate classes are doing, if the tasks are similar I would probably just combine them into once class. That would eliminate the problem altogether.