Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Cocoa 如何在基于NSDocument的应用程序中使用NSViewController_Cocoa_Xcode Storyboard_Nsdocument_Nswindowcontroller_Nsviewcontroller - Fatal编程技术网

Cocoa 如何在基于NSDocument的应用程序中使用NSViewController

Cocoa 如何在基于NSDocument的应用程序中使用NSViewController,cocoa,xcode-storyboard,nsdocument,nswindowcontroller,nsviewcontroller,Cocoa,Xcode Storyboard,Nsdocument,Nswindowcontroller,Nsviewcontroller,我对iOS有很多经验,但Cocoa让我有点困惑。我读了好几篇关于可可粉的苹果文档,但仍有一些细节我在任何地方都找不到。文档似乎是在基于NSDocument的Xcode模板更新为使用NSViewController之前编写的,因此我不清楚应该如何组织我的应用程序。该模板使用NSViewController窗口创建故事板 我的理解是,我可能应该将NSWindowController或NSWindow子类化,以引用我的模型对象,并在makeWindowController()中设置它。但是,如果我想使

我对iOS有很多经验,但Cocoa让我有点困惑。我读了好几篇关于可可粉的苹果文档,但仍有一些细节我在任何地方都找不到。文档似乎是在基于NSDocument的Xcode模板更新为使用NSViewController之前编写的,因此我不清楚应该如何组织我的应用程序。该模板使用NSViewController窗口创建故事板

我的理解是,我可能应该将NSWindowController或NSWindow子类化,以引用我的模型对象,并在makeWindowController()中设置它。但是,如果我想使用NSViewController,而不是将所有内容都放在窗口中,我还需要以某种方式访问那里的模型。我注意到在我的视图控制器中有一个叫做representedObject的东西,它看起来像是用来保存某个模型对象(然后进行转换),但它总是为零。这是怎么设置的

我发现很难正确表述这个问题,但我想我要问的是:如何在基于文档的应用程序中正确使用NSViewController


PS:我知道NSWindowController通常用于管理作用于一个文档的多个窗口,所以假设我只需要一个窗口,那么我就不需要NSWindowController。然而,需求可能会发生变化,从长远来看,使用NSWindowController可能会更好,对吗?

我自己对这方面比较陌生,但希望我能增加一些见解

您可以像在ios中一样使用视图控制器。您可以设置出口和目标等。对于基于NSDocument的应用程序,您可以使用视图控制器或窗口控制器,但我认为对于大多数应用程序,您最终会同时使用这两种控制器,并且大多数逻辑都在视图控制器中。把逻辑放在最有意义的地方。例如,如果nsdocument可以有多个窗口类型,则将视图控制器用于特定于每个类型的逻辑,将窗口控制器用于应用于所有类型的逻辑


representedObject属性主要与Cocoa绑定关联。虽然我开始熟悉绑定,但我没有足够的背景来详细介绍这里的内容。但是,通过bindings编程指南进行搜索可能会有所帮助。一般来说,绑定可以取代在ios上编写的大量数据源代码。当它起作用时,它是神奇的。当它不起作用时,就像调试魔术一样。看看哪里出了问题,这可能是一个挑战。

我没有深入到故事板中,但下面是它的工作原理:

如果您的应用程序必须支持10.9及更低版本,请创建自定义子类NSWindowController

将这样的代码放入NSDocument子类

- (void)makeWindowControllers
{
  CustomWindowController *controller = [[CustomWindowController alloc] init];
  [self addWindowController:controller];
}
如果您的应用程序有多个窗口,请将其添加到此处或其他位置(按需加载),但不要忘记将其添加到文档windowscontroller的数组中(addWindowController:)

如果您创建了这些窗口,但不想显示所有窗口,请覆盖它们

- (void)showWindows
{
  [controller showWindow:nil]
}
您可以随时在窗口控制器中访问您的模型

- (CustomDocument *)document
{
  return [self document];
}
[self.textView bind:@"editable"
                  toObject:self withKeyPath:@"document.readOnly"
                   options:@{NSValueTransformerNameBindingOption : NSNegateBooleanTransformerName}];
- (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];
}
在窗口控制器中使用绑定(windowcontroller子类+作为窗口控制器属性的keypath中的文档)

与iOS相比,大多数视图都在屏幕上,因此您必须依赖于模式:委派、通知、事件(响应者链),当然还有MVC

10.10约塞米蒂的变化:

NSViewController从开始自动添加到响应程序链中(通常操作的目标未知| NSApp sendAction:to:from:) 所有代理,如viewDidLoad。。。最终实现了iOS中熟悉的功能。这意味着我再也看不到子类化NSWindowCotroller的巨大好处了

NSDocument子类是必需的,NSViewController就足够了

您可以随时访问视图控制器中的数据

- (CustomDocument *)document
{
  return [self document];
}
[self.textView bind:@"editable"
                  toObject:self withKeyPath:@"document.readOnly"
                   options:@{NSValueTransformerNameBindingOption : NSNegateBooleanTransformerName}];
- (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];
}
如果您这样做(符合KVC/KVO),您可以按照上面所述进行绑定

小贴士: 正确执行文档中模型对象的撤消操作,例如,或羞耻地调用updateChangeCount:

[[self.undoManager prepareWithInvocationTarget:self] deleteRowsAtIndexes:insertedIndexes];
不要将与视图/窗口相关的代码放入文档中

将应用拆分为多个NSViewController,例如

- (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;
    }
}
在以viewcontroller作为代理的windowcontroller上调用上一代码(仅在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
#导入
@接口MyViewController:NSViewController
@属性(强)IBMOutlet NSView*viewToSubstitute;
@结束
#导入“MyViewController.h”
@接口MyViewController()
@结束
@MyViewController的实现
-(无效)从NIB中唤醒
{
NSView*view=[self view to substitute];
如果(视图){
[self-setViewToSubstitute:无];
[[self view]setFrame:[view frame]];
[[self-view]设置自动重新设置任务:[查看自动重新设置任务]];
[[view superview]replaceSubview:view with:[self view]];
}
}
@结束
  • 使用XIB将MyViewController的子类添加到项目中。重命名XIB
  • 将NSViewController对象添加到XIB并更改其子类名称
  • 将加载XIB名称从步骤1更改为名称
  • 将要替换的视图链接到要替换的视图 检查示例项目
  • 通过或激励自己

    真正的指南是使用和了解其他应用程序是如何完成的

    PS:您可以手动将视图/视图控制器添加到


    PS2:如果你是初学者,不要过度使用架构师。您的应用程序能够正常运行,请对此感到高兴。

    让我为简短答案类别添加一个简单的可复制样本

    在NSDocument子类中,当调用MakeWindowController时,将self发送到视图控制器的表示对象:

    - (void) makeWindowControllers
    { 
        NSStoryboard*                   storyboard          =   [NSStoryboard storyboardWithName: @"My Story Board" bundle: nil];
        NSWindowController*             windowController    =   [storyboard instantiateControllerWithIdentifier: @"My Document Window Controller"];
    MyViewController*    myController               =   (id) windowController.contentViewController;
        [self addWindowController: windowController];
        myController.representedObject = self;
    }
    
    在NSViewController的MyViewController子类中,覆盖setRepresentedObject以捕获其