vop*_*lif 6 cocoa nsdocument nsviewcontroller nswindowcontroller xcode-storyboard
我有很多iOS经验,但Cocoa让我有些困惑.我阅读了几篇关于Cocoa的Apple文档,但仍然有一些我在任何地方都找不到的细节.看来文档是在基于NSDocument的Xcode模板更新为使用NSViewController之前编写的,所以我不清楚我应该如何组织我的应用程序.该模板使用NSWindow NSViewController创建一个故事板.
我的理解是我应该将NSWindowController或NSWindow子类化为对我的模型对象的引用,并在makeWindowControllers()中设置它.但是,如果我想使用NSViewController而不是只是将所有内容放在窗口中,我还需要以某种方式访问我的模型.我注意到在我的视图控制器中有一个叫做RepresentObject的东西,它似乎意味着要保存一些模型对象(然后被强制转换),但它总是为零.这是如何设置的?
我发现很难正确地提出这个问题,但我想我的问题是:如何在基于文档的应用程序中正确使用NSViewController?
PS:我知道NSWindowController通常用于管理多个窗口,这些窗口作用于一个文档,所以假设我只需要一个窗口,那么我就不需要NSWindowController.但是,要求可能会改变,从长远来看使用NSWindowController可能会更好,对吧?
Mar*_*k H 14
我没有潜入故事板,但这是它的工作原理:
如果您的应用程序必须支持10.9及更低版本创建子类NSWindowController的自定义
将这样的代码放入NSDocument子类中
- (void)makeWindowControllers
{
CustomWindowController *controller = [[CustomWindowController alloc] init];
[self addWindowController:controller];
}
Run Code Online (Sandbox Code Playgroud)
如果你的应用程序有多个窗口而不是在这里或其他地方添加它们(按需加载)但不要忘记将它添加到文件windowscontroller数组(addWindowController :)
如果您创建它们但您不想显示所有窗口,则覆盖
- (void)showWindows
{
[controller showWindow:nil]
}
Run Code Online (Sandbox Code Playgroud)
您可以随时在窗口控制器中访问您的模型
- (CustomDocument *)document
{
return [self document];
}
Run Code Online (Sandbox Code Playgroud)
在窗口控制器中使用绑定(windowcontroller子类+ keypath中的文档,它是窗口控制器的属性)
[self.textView bind:@"editable"
toObject:self withKeyPath:@"document.readOnly"
options:@{NSValueTransformerNameBindingOption : NSNegateBooleanTransformerName}];
Run Code Online (Sandbox Code Playgroud)
与iOS相比,大多数视图都在屏幕上,因此您必须依赖模式:委派,通知,事件(响应者链),当然还有MVC.
10.10约塞米蒂变化:
从10.10开始的NSViewController 会自动添加到响应程序链中(通常目标操作未知| NSApp sendAction:to:from :)并且最终实现了从iOS熟悉的所有委托,如viewDidLoad.这意味着我不再看到子类化NSWindowCotroller的大好处了.
NSDocument子类是必需的,NSViewController就足够了.
您可以随时在视图控制器中访问您的数据
- (CustomDocument *)document
{
return (CustomDocument *)[[NSDocumentController sharedDocumentController] documentForWindow:[[self view] window]];
//doesn't work if you do template approach
//NSWindowController *controller = [[[self view] window] windowController];
//CustomDocument *document = [controller document];
}
Run Code Online (Sandbox Code Playgroud)
如果您喜欢这样(符合KVC/KVO),您可以按照上面的说明进行绑定.
提示:正确地为Document中的模型对象实现UNDO,例如或者可耻地调用updateChangeCount:
[[self.undoManager prepareWithInvocationTarget:self] deleteRowsAtIndexes:insertedIndexes];
Run Code Online (Sandbox Code Playgroud)
不要将与视图/窗口相关的代码放入文档中
将您的应用程序拆分为多个NSViewControllers,例如
- (void)prepareForSegue:(NSStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:AAPLListWindowControllerShowAddItemViewControllerSegueIdentifier]) {
AAPLListViewController *listViewController = (AAPLListViewController *)self.window.contentViewController;
AAPLAddItemViewController *addItemViewController = segue.destinationController;
addItemViewController.delegate = listViewController;
}
}
Run Code Online (Sandbox Code Playgroud)
在windowcontroller上调用以前的代码,并将viewcontroller作为委托(再次仅在10.10之后)
我总是喜欢使用多个XIB而不是一个巨型故事板/ XIB.使用以下NSViewController的子类并始终从它继承:
#import <Cocoa/Cocoa.h>
@interface MyViewController : NSViewController
@property(strong) IBOutlet NSView *viewToSubstitute;
@end
#import "MyViewController.h"
@interface MyViewController ()
@end
@implementation MyViewController
- (void)awakeFromNib
{
NSView *view = [self viewToSubstitute];
if (view) {
[self setViewToSubstitute:nil];
[[self view] setFrame:[view frame]];
[[self view] setAutoresizingMask:[view autoresizingMask]];
[[view superview] replaceSubview:view with:[self view]];
}
}
@end
Run Code Online (Sandbox Code Playgroud)


检查示例项目示例Multi XIB项目通过shapeart或lister或TextEdit来激励自己
一个真正的指南是使用Hopper并查看其他应用程序是如何完成的.
PS:您可以手动将views/viewcontroller添加到响应器链中.
PS2:如果你是初学者,不要过度建筑师.对您的应用程序运行这一事实感到满意.