Objective-C all instances for UI is nil

2019-01-20 18:12发布

问题:

I'm trying to do my first project in Objective-C/Xcode for Mac.

So far, I have just copied an example from GitHub (https://github.com/phae-girl/multi-view-controllers-xibs). It is an example of how to have 2 subviews inside a main window. The example works great, but when I add a button inside one of the views, the "- (IBAction)newButton:(id)sender{}" method for the new button shows both subviews as "nil". I'm confident it is a problem with access as textfields keep their value between switching views.

I have been searching for hours, so any kind of help is appreciated!

Ps.
To reproduce error with the GitHub project as base:
1. Drag'n'drop button into a subview
2. Add NSObject inside the view for the AppDelegate
3. ctrl-drag the button inside AppDelegate.h
4. Set breakpoint inside IBAction call in AppDelegate.m

回答1:

"Add NSObject inside the view for the App Delegate" is not what you want to do. If you do that and set the class to the project's AppDelegate class, you just created a second instance of AppDelegate that is not [NSApp delegate]. And unlike [NSApp delegate], your new instance doesn't have its view controller properties initialized to the outlets from MainMenu.xib

See my fantastic question here for more discussion. Trust me, I feel your pain. If you do this in the IBAction, it should confirm separate instance addresses:

NSLog(@"This instance address: %p",self);
NSLog(@"True app delegate address: %p",[NSApp delegate]);

The key thing to understand is that the objects in the NIB are created when the NIB is loaded, and IBOutlets are pointers to those objects. It's all too easy to think of the NIB objects as pointers to objects in your code, but it's truly the opposite. The placeholders make it easy to be lead astray in this regard.

Anyways, to fix your issue...

You have to subclass NSViewController and make the custom class of File's Owner in the subview xib your new subclass, and also make sure the correct view controller instance in MainMenu.xib is your new subclass. And then, you can connect the IBAction from the subview to the custom class header, and Xcode will recognize the association between the new subclass and the subview NIB because you've set the class of File's Owner. I believe you'll then be hooked up to the right instances based on the way things are done in the project you linked to, but if not, there's this question to consider.

There's no good way have the subview NIBs call methods in the AppDelegate class. Best to think of it as there only for the main menu (Quit, Save, Undo, etc) and not for any views. (With the caveat that the "fantastic question" shows an ugly way to make it work.)

You could have the code in your custom NSViewController subclass refer back to [NSApp delegate] -- shorthand for [[NSApplication sharedApplication] delegate] -- if needed, though you are best to avoid that.