macOS 开发 - NSWindow、NSWindowController、NSViewController、NSView 的关系和创建

本文详细解析了macOS开发中NSWindow、NSWindowController、NSViewController和NSView四大组件之间的关系,介绍了它们各自的作用及如何协作构建应用界面,包括创建、配置及显示窗口的具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2018年03月08日 17:01:26 lovechris00 阅读数:2487收起

所属专栏: macOS 开发

 

版权声明:本文为博主原创文章,转载请附上本文链接地址。from : https://blog.youkuaiyun.com/lovechris00 https://blog.youkuaiyun.com/lovechris00/article/details/79486949

 

  • 一、NSWindow、NSWindowController、NSViewController、NSView 之间的关系
    • 1、NSWindowController 管理 NSWindow 之间的交互;
    • 2、NSViewController 管理 NSWindow 内容的展示
    • 3、NSViewController 内容为 NSView
  • 二、创建 NSWindow
    • 设置window的内容
      • 1、设置contentView
      • 2、设置 contentViewController
      • 3、设置 contentViewController 同时往 contentView 上添加东西
  • 三、创建 NSWindowController
    • 1、不勾选xib
      • 1.1 使用 init 初始化,无法正常显示窗口
      • 1.2 使用 initWithWindow 初始化,可以显示窗口
    • 2、勾选xib
      • 2.1 使用 initWithWindowNibName 初始化,可以正常显示窗口
      • 2.2 使用 init 初始化,无法正常显示窗口
  • 四、NSViewController
    • 1、创建时不勾选xib
      • 1.1 使用 init 方法初始化,显示 window 失败。
      • 1.2 初始化 NSViewController,并设置view,显示成功
    • 2、勾选xib
      • 2.1 使用 initWithNibName 初始化,加载成功
      • 2.2使用 init 方法初始化,加载成功,效果同上。
  • 五、综合、不显示的问题等
    • 1、NSWindow or NSWindowController 需要被强引用
    • 2、示例:NSView –>NSViewController–>NSWindow–>NSWindowController
    • 3、示例 NSView–>NSWindow–>NSWindowController
  • 参考资料

 

 

一、NSWindowNSWindowControllerNSViewControllerNSView 之间的关系

1NSWindowController 管理 NSWindow 之间的交互;

NSWindowController 有一个属性为 window ,使用 initWithWindow 初始化时,可以设置自定义的 window 为自己的 window。

 

2NSViewController 管理 NSWindow 内容的展示

NSWindow 的内容由contentViewController 和 contentView 决定。

contentViewController 是一个 NSViewController 类;用 NSViewController 来管理 NSWindow 内容的展示更方便。

设置 某个 NSViewController 子类a 为 NSWindow 的 contentViewController 后:

window.contentView = window.contentViewController.view = a.view

 

3NSViewController 内容为 NSView

NSViewController 的内容由一个个的 NSView 决定。

 

二、创建 NSWindow

创建项目后,删除工程自带的 xib中的window,在delegate中添加 NSWindow 属性

@property(nonatomic,strong) NSWindow *window1;

 

懒加载初始化,并在启动时展示出来

-(NSWindow *)window1{

    if (!_window1) {

        NSUInteger style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable ;

        _window1 = [[NSWindow alloc]initWithContentRect:CGRectMake(0, 0, 200, 300) styleMask:style backing:NSBackingStoreBuffered defer:YES];

//        _window1.contentViewController = self.firstVC;

    }

    return _window1;

}

 

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {

        [self.window1 center];

        [self.window1 orderFront:nil];

}

运行程序,就可以看到我们创建的window了。

window的样式这里不累述了,可参考文章:MacOS 开发 - NSWindow 自定义样式 : http://blog.youkuaiyun.com/lovechris00/article/details/77943884

 

设置window的内容

 

1、设置contentView

往 contentView 添加内容

OneView *view = [[OneView alloc]initWithFrame:CGRectMake(0, 0, 200, 200)];

[self.window.contentView addSubview:view];

其中 OneView 继承自 NSView,并在 OneView.m 中添加自定义设置

- (void)drawRect:(NSRect)dirtyRect {

    [super drawRect:dirtyRect];

 

    self.wantsLayer = YES;

    self.layer.backgroundColor = [NSColor cyanColor].CGColor;

}

 

2、设置 contentViewController

self.window.contentViewController = [[FirstViewController alloc]init];

这个窗口的显示内容,由 FirstViewController 决定。

 

设置完 contentViewController 后,window.contentView 就是 self.window.contentViewController.view

我们写下如下测试代码:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {

 

 

    NSLog(@"contentViewController : %@ , Controller.view : %@ , contentView : %@",self.window.contentViewController,self.window.contentViewController.view,self.window.contentView);

 

    self.window.contentViewController = [[FirstViewController alloc]init];

 

    NSLog(@"contentViewController : %@ , Controller.view : %@ , contentView : %@",self.window.contentViewController,self.window.contentViewController.view,self.window.contentView);

}

打印日志如下:

2018-03-08 16:00:22.344709+0800 MSWindowDemo[3030:262893] contentViewController : (null) ,

Controller.view : (null) ,

contentView : <NSView: 0x604000120aa0>

 

2018-03-08 16:00:22.347321+0800 MSWindowDemo[3030:262893] contentViewController : <FirstViewController: 0x6000000c2e60> ,

Controller.view : <NSView: 0x600000122800> ,

contentView : <NSView: 0x600000122800>

3、设置 contentViewController 同时往 contentView 上添加东西

效果按照添加顺序叠加

3.1 如果先设置 contentViewController ,再往 contentView 上添加控件。实际上是往 contentViewController.view 上添加控件。效果如下:

 

3.2 如果先添加 contentView,再设置 contentViewController,contentViewController的内容会覆盖之前的设置。效果同 2.

 

 

三、创建 NSWindowController

创建项目后,删除工程自带的 xib中的window,创建继承自 NSWindowController 的类,弹出该控制器的 window.

delegate中弹窗部分代码如下:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {

 

    [self.firstWindowC.window center];

    [self.firstWindowC.window orderFront:nil];

}

1、不勾选xib

1.1 使用 init 初始化,无法正常显示窗口

_firstWindowC = [[FirstWindowController alloc]init];

1.2 使用 initWithWindow 初始化,可以显示窗口

        NSUInteger style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable ;

        NSWindow *window0 = [[NSWindow alloc]initWithContentRect:CGRectMake(0, 0, 400, 200) styleMask:style backing:NSBackingStoreBuffered defer:YES];

        _firstWindowC = [[FirstWindowController alloc]initWithWindow:window0];

 

2、勾选xib

2.1 使用 initWithWindowNibName 初始化,可以正常显示窗口

_secWindowC = [[SecWindowController alloc]initWithWindowNibName:@"SecWindowController"];

2.1.1 在 windowDidLoad 中设置window,无法设置frame

 

2.1.2 在 windowDidLoad 中设置 self.window 指针,会弹出两个窗口

- (void)windowDidLoad {

    [super windowDidLoad];

 

    NSUInteger style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable ;

    NSWindow *window0 = [[NSWindow alloc]initWithContentRect:CGRectMake(0, 0, 200, 300) styleMask:style backing:NSBackingStoreBuffered defer:YES];

 

    self.window = window0;

}

 

2.2 使用 init 初始化,无法正常显示窗口

_secWindowC = [[SecWindowController alloc]init];

 

2.2.1 在 windowDidLoad 中设置 self.window 指针(代码同 2.1.2),还是无法正常显示窗口

2.2.2 使用 initWithWindow 初始化,会弹出窗口,效果同 1.2

跟初始化的 xib 中的窗口无关了。

 

四、NSViewController

创建 FirstViewController 继承自 NSViewController,并将 FirstViewController 示例设置为 window.contentViewController

1、创建时不勾选xib

1.1 使用 init 方法初始化,显示 window 失败。

self.window.contentViewController = [[FirstViewController alloc]init];

1.2 初始化 NSViewController,并设置view,显示成功

-(SecViewController *)secVC{

    if (!_secVC) {

        _secVC = [[SecViewController alloc]init];

        NSView *view = [[NSView alloc]initWithFrame:CGRectMake(0, 0, 200, 100)];

        view.wantsLayer = YES;

        view.layer.backgroundColor = [NSColor yellowColor].CGColor;

        _secVC.view = view;

 

    }

    return _secVC;

}

 

self.window1.contentViewController = self.secVC;

 

 

2、勾选xib

2.1 使用 initWithNibName 初始化,加载成功

self.window.contentViewController = [[FirstViewController alloc]initWithNibName:@"FirstViewController" bundle:nil];

 

2.2使用 init 方法初始化,加载成功,效果同上。

self.window.contentViewController = [[FirstViewController alloc]init];

 

于是我想测试下,是否偷偷调用了 initWithNibName 方法,在 FirstViewController.m 中写下如下代码:

@implementation FirstViewController

 

-(instancetype)init{

    self = [super init];

    NSLog(@"First : init");

    return self;

}

 

-(instancetype)initWithNibName:(NSNibName)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{

 

   self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

 

    NSLog(@"First nibNameOrNil : %@ , nibBundleOrNil : %@",nibNameOrNil,nibBundleOrNil);

 

    return self;

}

再次运行,发现打印日志如下:

2018-03-08 16:46:56.625786+0800 MSWindowDemo[3919:297186] First nibNameOrNil : (null) , nibBundleOrNil : (null)

2018-03-08 16:46:57.896924+0800 MSWindowDemo[3919:297186] First : init

说明使用 init 方法会默认调用 initWithNibName 方法去寻找 xib文件。

 

五、综合、不显示的问题等

1NSWindow or NSWindowController 需要被强引用

//显示失败

- (void)test4{

 

    FirstWindowController *firstWC = [[FirstWindowController alloc]initWithWindowNibName:@"FirstWindowController"];

    [firstWC.window orderFront:nil];

    [firstWC.window center];

}

需要改为:

//显示成功

- (void)test4{

 

    FirstWindowController *firstWC = [[FirstWindowController alloc]initWithWindowNibName:@"FirstWindowController"];

    [firstWC.window orderFront:nil];

    [firstWC.window center];

 

    self.firstWC = firstWC;

 

}

部分情况下,window 可能会显示出来,但是 window 上的按钮可能点击无效。

 

2、示例:NSView –>NSViewController–>NSWindow–>NSWindowController

这样创建的逻辑是没有问题的,但是 window 不会显示出来;

原因是,不知道 window 的大小;

解决方法,初始化 NSView 的时候,要设置 frame; 那么 window 的大小就会是这个 view.frame;

代码可改为如下

//可以显示,且窗口大小为 view 的大小:{300,300}

- (void)test3{

 

    NSView *view = [[NSView alloc]initWithFrame:NSMakeRect(0, 0, 300, 300)];

    view.wantsLayer = YES;

    view.layer.backgroundColor = [NSColor redColor].CGColor;

 

    NSViewController *viewController = [[NSViewController alloc]init];

    viewController.view = view;

 

    NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;

    NSRect rect = NSMakeRect(0, 0, 400, 200);

    NSWindow *window = [[NSWindow alloc]initWithContentRect:rect styleMask:styleMask backing:NSBackingStoreBuffered defer:YES];

    window.contentViewController = viewController;

 

    self.windowController = [[NSWindowController alloc]initWithWindow:window];

    [self.windowController.window center];

    [self.windowController.window orderFront:nil];

 

}

 

3、示例 NSView–>NSWindow–>NSWindowController

//显示成功

- (void)test2{

 

    NSView *view0 = [[NSView alloc]initWithFrame:NSMakeRect(0, 0, 400, 400)];

    view0.wantsLayer = YES;

    view0.layer.backgroundColor = [NSColor redColor].CGColor;

 

    NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;

    NSRect rect = NSMakeRect(0, 0, 400, 200);

    NSWindow *window = [[NSWindow alloc]initWithContentRect:rect styleMask:styleMask backing:NSBackingStoreBuffered defer:YES];

    window.contentView = view0;

 

    self.windowController = [[NSWindowController alloc]initWithWindow:window];

    [self.windowController.window center];

    [self.windowController.window orderFront:nil];

 

}

 

参考资料

http://blog.youkuaiyun.com/fl2011sx/article/details/73252859

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值