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.
Related
Something very strange is going on with my interface builder. So I created an NSWindowController subclass in Xcode, with the create XIB option enabled. I started coding, and I successfully connected to file's owner.
But, when I run my app, I get the error :
Failed to connect (workspaceControl) outlet from (NSWindowController) to (NSSegmentedControl): missing setter or instance variable
Failed to connect (workspaceField) outlet from (NSWindowController) to (NSTextField): missing setter or instance variable
Could not connect action, target class NSWindowController does not respond to -changeNumberOfWorkspaces:
I don't know why this error is showing up as I have my code set up right:
And the File's owner is set to the right class (AddController):
So why does it try to connect my views to NSWindowController instead of my subclass?
EDIT:
Where I actually use the AddController in code:
AppDelegate.h
AppDelegate.m
It's in appdelegate because it is a menubar app. (In case anyone was wondering)
Because the actual object that is instantiated in your running program is an NSWindowController, not an AddController. You've shown us that AddController is properly declared, and you've shown us that your nib's File's Owner is set to AddController; that's great, and is why you don't get a compile-time warning or error about things being wired up incorrectly. But you haven't shown us where the controller object actually gets instantiated; and examining that would presumably reveal that it hasn't been changed to AddController. So at runtime you've got an NSWindowController, in violation of what you promised to IB would be the case; and so you get runtime errors.
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.
I come from a Cocoa touch background and there's one point I'm stuck on, I'm trying to create a ViewController from scratch and connect objects in my xib to actions in my new ViewController. I changed the file's owner to my ViewController and added outlets, and the compiler seems to be happy with what I've done.
But when I run my application, the connections seem to fail with: 'Could not connect the action start: to target of class NSApplication,' but where is this NSApplication reference hiding? To the best of my knowledge my ViewController has a class of NSViewController.
ViewController : NSViewController
I changed the file's owner to my ViewController and added outlets, and the compiler seems to be happy with what I've done.
Sure, the compiler won't care -- this is a run-time error. It sounds like you're working in your MainMenu.xib file. That file is loaded by the application object. Even though you changed the type of File's Owner in the .xib, the object that's loading the .xib is still the application.
You'll probably want to create a separate .xib file for your view controller to load. You change the type of File's Owner in that file to you view controller class! hook things up to File's Owner, and it should work fine since your view controller really will be the object that's loading the file.
I downloaded the sample xamarin.mac hello world project and when I try to run I get a null reference exception on the outletes when it runs. I see the outlets get properties set to them in the MainWindow.designer.cs partial classes but when it tries to reference them in MainWindowController.cs a null reference exception is thrown.
How does the sample project work when the property definitions are in the MainWindow.cs partial class and not in the controller class. Is the sample project supposed to work out of the box?
I am not familiar with the hello world example, but I come across this problem all the time in native Mac/Xcode land and I just hit it again inside Xamarin Studio. My problem happened to be this: I have a GUI full of NSTextFields. I wired each in turn to a new outlet in MainWindowController.h, however I accidentally re-wired the second NSTextField in my list to the outet I'd previously defined for the first TextField. This automatically disconnects the previous link, and even though the outlet remains defined in the .h, the connection in the .xib is broken and thus the first outlet never gets initialized with the xib's NSTextField instance.
The solution is basically right-click the GUI element in question in interface builder and be sure its referencing outlet is actually wired up to the outlet you expect in the .h.
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.