如何在基于NSDocument的Cocoa应用程序中使用NSViewController [英] How to use NSViewController in an NSDocument-based Cocoa app

查看:111
本文介绍了如何在基于NSDocument的Cocoa应用程序中使用NSViewController的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在iOS方面拥有丰富的经验,但可可让我有些困惑。我通读了关于Cocoa的几份Apple文档,但是仍然有一些我找不到的细节。似乎该文档是在将基于NSDocument的Xcode模板更新为使用NSViewController之前编写的,因此,我不清楚应如何组织应用程序。该模板使用NSWindow NSViewController创建一个情节提要。



我的理解是,我应该将NSWindowController或NSWindow子类化,以引用我的模型对象,并在makeWindowControllers()中进行设置。但是,如果我想使用NSViewController而不是将所有内容都放在窗口中,那么我也需要以某种方式访问​​我的模型。我注意到在我的视图控制器中有一个叫做namedObject的东西,似乎是要保存一些模型对象(然后进行转换),但始终为零。



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



PS:我知道NSWindowController通常是要管理作用于一个文档的多个窗口,所以大概我只需要一个窗口就可以了。不需要NSWindowController。但是,需求可能会发生变化,从长远来看,使用NSWindowController可能会更好,对吧?

解决方案

我还没有深入研究故事板,但是它是这样工作的:



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





将这样的代码放入NSDocument子类中

 -(void)makeWindowControllers 
{
CustomWindowController * controller = [[CustomWindowController alloc] init];
[self addWindowController:controller];
}

如果您的应用有多个窗口,则不要在此处或其他位置添加它们(加载到需求),但不要忘记将其添加到文档Windowscontroller数组中(addWindowController:)



如果创建它们,但又不想显示所有窗口,则可以覆盖

 -(void)showWindows 
{
[controller showWindow:nil]
}

您可以随时在窗口控制器中访问模型

 -(CustomDocument *)document 
{
return [自身文档];
}

在窗口控制器中使用绑定(windowcontroller子类+键路径中的文档是窗口控制器的属性)

  [self.textView bind:@ editable 
toObject:self withKeyPath:@ document.readOnly
选项:@ {NSValueTransformerNameBindingOption:NSNegateBooleanTransformerName}];

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



10.10优胜美地变更:




  • 更改在步骤1中将XIB名称加载到名称中

  • 链接视图以替换为要替换的视图

    检查示例项目示例Multi XIB项目

  • 通过 shapeart 列表 TextEdit



    真正的指南是使用 Hopper



    PS:您可以将视图/视图控制器添加到响应者链



    PS2:如果您是初学者,请不要过度设计。对您的应用程序正常运行感到满意。


    I've got plenty of experience with iOS, but Cocoa has me a bit confused. I read through several Apple docs on Cocoa but there are still details that I could not find anywhere. It seems the documentation was written before the NSDocument-based Xcode template was updated to use NSViewController, so I am not clear on how exactly I should organize my application. The template creates a storyboard with an NSWindow, NSViewController.

    My understanding is that I should probably subclass NSWindowController or NSWindow to have a reference to my model object, and set that in makeWindowControllers(). But if I'd like to make use of the NSViewController instead of just putting everything in the window, I would also need to access my model there somehow too. I notice there is something called a representedObject in my view controller which seems like it's meant to hold some model object (to then be cast), but it's always nil. How does this get set?

    I'm finding it hard to properly formulate this question, but I guess what I'm asking is:how do I properly use NSViewController in my document-based application?

    PS: I understand that NSWindowController is generally meant to managing multiple windows that act on one document, so presumably if I only need one window then I don't need an NSWindowController. However, requirements might change and having using NSWindowController may be better in the long run, right?

    解决方案

    I haven't dived into storyboards but here is how it works:

    If your app has to support 10.9 and lower create custom of subclass NSWindowController

    Put code like this into NSDocument subclass

    - (void)makeWindowControllers
    {
      CustomWindowController *controller = [[CustomWindowController alloc] init];
      [self addWindowController:controller];
    }
    

    If your app has multiple windows than add them here or somewhere else (loaded on demand) but do not forget to add it to array of document windowscontroller (addWindowController:)

    If you create them but you don't want to show all the windows then override

    - (void)showWindows
    {
      [controller showWindow:nil]
    }
    

    You can anytime access you model in your window controller

    - (CustomDocument *)document
    {
      return [self document];
    }
    

    Use bindings in your window controller (windowcontroller subclass + document in the keypath which is a property of window controller)

    [self.textView bind:@"editable"
                      toObject:self withKeyPath:@"document.readOnly"
                       options:@{NSValueTransformerNameBindingOption : NSNegateBooleanTransformerName}];
    

    In contrast to iOS most of the views are on screen so you have to rely on patterns: Delegation, Notification, Events (responder chain) and of course MVC.

    10.10 Yosemite Changes:

    NSViewController starting from 10.10 is automatically added to responder chain (generally target of the action is unknown | NSApp sendAction:to:from:) and all the delegates such as viewDidLoad... familiar from iOS are finally implemented. This means that I don't see big benefit of subclassing NSWindowCotroller anymore.

    NSDocument subclass is mandatory and NSViewController is sufficient.

    You can anytime access you data in your view controller

    - (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];
    }
    

    If you do like this (conforming to KVC/KVO) you can do binding as written above.

    Tips: Correctly implement UNDO for your model objects in Document e.g. or shamefully call updateChangeCount:

    [[self.undoManager prepareWithInvocationTarget:self] deleteRowsAtIndexes:insertedIndexes];
    

    Do not put code related to views/windows into your Document

    Split your app into multiple NSViewControllers e.g.

    - (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;
        }
    }
    

    Previous code is called on windowcontroller with viewcontroller as delegate (again possible only after 10.10)

    I always prefer to use multiple XIBs rather than one giant storyboard/XIB. Use following subclass of NSViewController and always inherit from it:

    #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
    

    1. Add a subclass of MyViewController to the project with XIB. Rename the XIB
    2. Add NSViewController Object to the XIB and change its subclass name
    3. Change the loading XIB name to name from step 1
    4. Link view to substitute to the view you want to replace Check example project Example Multi XIB project

    Inspire yourself by shapeart or lister or TextEdit

    And a real guide is to use Hopper and see how other apps are done.

    PS: You can add your views/viewcontroller into responder chain manually.

    PS2: If you are beginner don't over-architect. Be happy with the fact that your app works.

    这篇关于如何在基于NSDocument的Cocoa应用程序中使用NSViewController的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆