我读到您应该使用 NSWindowController 来管理窗口。见这里:
Windows and window controllers
Adding views or windows to MainWindow
如果你的窗口变得足够复杂,NSWindowController 可以使用各种 NSViewController 来管理窗口的各个部分。
无论如何,我在回答中使用了 NSWindowController。
下图显示了文件所有者的出口,即我的MainWindowController:
我在Xcode6.2 中通过以下方式创建了 MainWindowController .h/.m:
- 选择文件>新建>文件>OS X - 源代码 - Cocoa 类
- 为
Subclass of: 选择 NSWindowController
- 检查
also create .xib file for user interface
然后我删除了默认 MainMenu.xib 中的窗口(不是菜单),并将通过上述步骤创建的 MainWindowController.xib 的名称更改为 MainWindow.xib。
以下代码适用于我(但我是 Cocoa 初学者!):
//
// AppDelegate.m
// PopUpButtons
#import "AppDelegate.h"
#import "MainWindowController.h"
@interface AppDelegate ()
@property(strong) MainWindowController* mainWindowCtrl;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
[self setMainWindowCtrl:[[MainWindowController alloc] init]];
[[self mainWindowCtrl] showWindow:nil];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
@end
...
//
// MainWindowController.m
// PopUpButtons
//
#import "MainWindowController.h"
#import "MyData.h"
@interface MainWindowController ()
@property(strong) MyData* data;
@property(weak) IBOutlet NSPopUpButton* namePopUp;
@property(weak) IBOutlet NSPopUpButton* agePopUp;
@end
@implementation MainWindowController
-(id)init {
if (self = [super initWithWindowNibName:@"MainWindow"]) {
_data = [[MyData alloc] init]; //Get data for popups
}
return self;
}
- (void)windowDidLoad {
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
[[self namePopUp] removeAllItems];
[[self namePopUp] addItemsWithTitles:[[self data] drinks]];
[[self agePopUp] removeAllItems];
[[self agePopUp] addItemsWithTitles:[[self data] extras]];
}
@end
...
//
// MyData.h
// PopUpButtons
//
#import <Foundation/Foundation.h>
@interface MyData : NSObject
@property NSArray* drinks;
@property NSArray* extras;
@end
...
//
// MyData.m
// PopUpButtons
//
#import "MyData.h"
@implementation MyData
- (id)init {
if (self = [super init]) {
_drinks = @[@"coffee", @"tea"];
_extras = @[@"milk", @"sugar", @"honey"];
}
return self;
}
@end
我希望这会有所帮助。如果您需要更多截图,请告诉我。
编辑1:
我想我明白你在问什么。虽然我认为这不是一个很好的方法,但如果我将代码更改为:
//
// MyData.h
// PopUpButtons
//
#import <Cocoa/Cocoa.h>
@interface MyData : NSObject
@property (copy) NSArray* drinks;
@property (copy) NSArray* extras;
-(void)newRequest;
@end
...
//
// MyData.m
// PopUpButtons
//
#import "MyData.h"
@interface MyData()
@property (weak) IBOutlet NSPopUpButton* drinksPopUp;
@property (weak) IBOutlet NSPopUpButton* extrasPopUp;
@end
@implementation MyData
- (id)init {
if (self = [super init]) {
_drinks = @[@"coffee", @"tea"];
_extras = @[@"milk", @"sugar", @"honey"];
}
return self;
}
-(void)newRequest {
[[self drinksPopUp] removeAllItems];
[[self drinksPopUp] addItemsWithTitles:[self drinks]];
[[self extrasPopUp] removeAllItems];
[[self extrasPopUp] addItemsWithTitles:[self extras]];
}
@end
我无法填充 NSPopUpButtons。这就是我所做的:
我将一个对象从对象库拖到 IB 的停靠栏中,然后在身份检查器中,我将对象的类更改为 MyData。
然后我点击 Connections Inspector,MyData 中的两个实例变量drinksPopUp 和 extrasPopUp 被列在 Outlets 中。
我从插座拖到相应的 NSPopUpButtons。
我想我和你一样认为,当我的程序运行时,NSPopUpButtons 将被分配给实例变量drinksPopUp 和 extrasPopUp——但情况似乎并非如此。根据Apple docs,您应该可以这样做:
应用程序通常会在其自定义之间设置出口连接
控制器对象和用户界面上的对象,但它们可以是
在可以表示为实例的任何对象之间创建
界面生成器,...
编辑2:
我可以将 MainWindowController 中的 NSPopUpButtons 传递给 newRequest 方法,并且可以使用 newRequest 中的 NSPopUpButtons 成功填充数据。
编辑3:
我知道自定义类 (newRequest) 中的方法有效,因为
我添加了一个 NSLog 命令来在方法执行时打印“Test”。
但是当您记录指向 NSPopUpButtons 的变量时会发生什么?使用Edit1 中的代码,我得到的变量为 NULL,这意味着 NSPopUpButtons 从未被分配给变量。
编辑4:
如果我将 awakeFromNib 方法添加到 MyData,并在 awakeFromNib 中记录 Edit1 中代码的 NSPopUpButton 变量,我会得到非 NULL 值。这告诉我 MainWindowController 的 windowDidLoad 方法在 MyData 的 awakeFromNib 方法之前执行,因此您不能在 MainWindowController 的 windowDidLoad 方法中调用 newRequest,因为 MyData 尚未完全初始化。
编辑5:
好的,我让 Edit1 中的代码工作了。 Apple docs 这么说:
关于顶级对象
当您的程序加载一个 nib 文件时,Cocoa 会重新创建整个图形
您在 Xcode 中创建的对象。该对象图包括所有
窗口、视图、控件、单元格、菜单和自定义对象
笔尖文件。顶级对象是这些对象的子集
没有父对象[在 IB 中]。顶级对象通常
仅包括窗口、菜单栏和自定义控制器对象
您添加到 nib 文件 [如 MyData 对象]。 (文件的所有者等对象,首先
Responder 和 Application 是占位符对象,不予考虑
顶级对象。)
通常,您使用 File’s Owner 对象中的 outlet 来存储
对 nib 文件的顶级对象的引用。 如果您不使用
但是,您可以从
笔尖加载例程直接。您应该始终保留指向
这些对象在某处,因为您的应用程序负责
使用完毕后释放它们。有关更多信息
加载时 nib 对象的行为,请参阅管理
来自 Nib 文件的对象。
按照上面加粗的那一行,我在MainWindowController.m中修改了这个声明:
@interface MainWindowController ()
@property(strong) MyData* data;
...
@end
到这里:
@interface MainWindowController ()
@property(strong) IBOutlet MyData* data;
...
@end
然后,在 IB 中,我将连接从 MainWindowController data 出口拖到 MyData 对象(我之前从对象库拖到文档中的对象)。
我猜这会导致 MyData 从 .xib 文件中取消归档并在 MainWindowController 之前初始化。