NSViewController
简介
NSViewController
是 macOS 应用程序中的核心类,用于管理单个视图层次结构。它提供了对视图生命周期、布局管理和内容更新的控制,并与模型数据和其他控制器进行交互,提供了高效的视图控制和管理机制。
基础知识点
NSViewController
继承自 NSResponder
,它主要用于以下几方面:
- 视图层次结构管理:管理视图及其子视图。
- 视图生命周期管理:管理视图的加载、显示、隐藏和销毁生命周期。
- 与数据模型交互:通过关联的模型数据来更新视图内容。
- 事件响应:处理用户交互事件。
常见 API 和方法
初始化与视图管理
初始化视图控制器
Objective-C
- (instancetype)initWithNibName:(NSNibName)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil;
Swift
init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?)
加载视图
会在视图第一次访问时调用,通常在这里执行一些视图初始化工作。
Objective-C
- (void)loadView {
self.view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 200, 200)];
}
Swift
override func loadView() {
self.view = NSView(frame: NSRect(x: 0, y: 0, width: 200, height: 200))
}
视图生命周期
视图即将出现
Objective-C
- (void)viewWillAppear;
Swift
override func viewWillAppear() {
super.viewWillAppear()
}
视图已经出现
Objective-C
- (void)viewDidAppear;
Swift
override func viewDidAppear() {
super.viewDidAppear()
}
视图即将消失
Objective-C
- (void)viewWillDisappear;
Swift
override func viewWillDisappear() {
super.viewWillDisappear()
}
视图已经消失
Objective-C
- (void)viewDidDisappear;
Swift
override func viewDidDisappear() {
super.viewDidDisappear()
}
子视图管理
添加子视图控制器
Objective-C
- (void)addChildViewController:(NSViewController *)childViewController;
Swift
func addChild(_ childViewController: NSViewController)
移除子视图控制器
Objective-C
- (void)removeFromParentViewController;
Swift
func removeFromParent()
切换子视图控制器
Objective-C
- (void)transitionFromViewController:(NSViewController *)fromViewController
toViewController:(NSViewController *)toViewController
options:(NSViewControllerTransitionOptions)options
completionHandler:(void (^)(void))completion;
Swift
func transition(from fromViewController: NSViewController, to toViewController: NSViewController, options: NSViewController.TransitionOptions = [], completionHandler completion: (() -> Void)? = nil)
数据绑定和更新
绑定模型数据
可以使用 @IBOutlet
和 @IBAction
将视图控件连接到代码中。
Objective-C
@interface MyViewController : NSViewController
@property (weak) IBOutlet NSTextField *textField;
@end
@implementation MyViewController
- (IBAction)buttonClicked:(id)sender {
self.textField.stringValue = @"Button clicked!";
}
@end
Swift
class MyViewController: NSViewController {
@IBOutlet weak var textField: NSTextField!
@IBAction func buttonClicked(_ sender: Any) {
textField.stringValue = "Button clicked!"
}
}
自定义布局和自动布局
手动布局视图
Objective-C
- (void)viewDidLayout {
[super viewDidLayout];
self.view.subviews[0].frame = NSMakeRect(10, 10, 100, 100);
}
Swift
override func viewDidLayout() {
super.viewDidLayout()
self.view.subviews[0].frame = NSMakeRect(10, 10, 100, 100)
}
使用自动布局
Objective-C
- (void)viewDidLoad {
[super viewDidLoad];
NSView *subview = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
[subview setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:subview];
[self.view addConstraints:@[
[subview.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:10],
[subview.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-10],
[subview.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:10],
[subview.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-10]
]];
}
Swift
override func viewDidLoad() {
super.viewDidLoad()
let subview = NSView(frame: NSRect(x: 0, y: 0, width: 100, height: 100))
subview.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(subview)
NSLayoutConstraint.activate([
subview.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 10),
subview.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -10),
subview.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 10),
subview.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -10)
])
}
视图交互和事件响应
响应用户事件
可以为视图添加手势识别器或继承 NSView
的事件方法。
Objective-C
- (void)viewDidLoad {
[super viewDidLoad];
NSClickGestureRecognizer *clickRecognizer = [[NSClickGestureRecognizer alloc] initWithTarget:self action:@selector(handleClick:)];
[self.view addGestureRecognizer:clickRecognizer];
}
- (void)handleClick:(NSGestureRecognizer *)gestureRecognizer {
NSLog(@"View clicked!");
}
Swift
override func viewDidLoad() {
super.viewDidLoad()
let clickRecognizer = NSClickGestureRecognizer(target: self, action: #selector(handleClick(_:)))
self.view.addGestureRecognizer(clickRecognizer)
}
@objc func handleClick(_ gestureRecognizer: NSGestureRecognizer) {
print("View clicked!")
}
深入探讨
视图控制器生命周期
理解 NSViewController
的生命周期方法对正确处理视图的呈现和销毁非常重要。
init(nibName:bundle:)
:初始化视图控制器。通常用于从 NIB/XIB 文件中加载视图。loadView
:视图控制器的主视图在第一次访问时会调用该方法。这是设置视图层次结构的好时机。viewDidLoad
:视图层次结构已载入到内存时调用。适用于额外的初始化工作,比如设置控件的初始状态。viewWillAppear
:视图即将加入视图层级时调用。适用于每次视图显示前需要进行的操作,比如更新数据。viewDidAppear
:视图已经加入视图层级时调用。适用于视图已经显示后的操作,比如启动动画。viewWillDisappear
:视图即将从视图层级移除时调用。适用于移除前需要进行的操作,例如停止动画或者解除绑定。viewDidDisappear
:视图已经从视图层级移除时调用。适用于视图已经消失后的操作,比如保存数据。
动态加载和卸载视图
在内存有限或者视图控件复杂的情况下,可以考虑动态加载和卸载部分视图。
Objective-C
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
if (self.isViewLoaded && !self.view.window) {
self.view = nil;
}
}
Swift
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
if self.isViewLoaded && self.view.window == nil {
self.view = nil
}
}
模块化开发和复用性
NSViewController
可以用于构建模块化的 UI 组件,使得各个部分可以独立开发和测试,然后再组合成完整的界面。
Objective-C
@interface CustomViewController : NSViewController
@end
@implementation CustomViewController
- (instancetype)init {
if (self = [super initWithNibName:nil bundle:nil]) {
}
return self;
}
- (void)loadView {
// 模块化视图初始化
self.view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 200, 200)];
// 添加更多子视图或控件
}
@end
Swift
class CustomViewController: NSViewController {
override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
// 初始化代码
}
required init?(coder: NSCoder) {
super.init(coder: coder)
// 初始化代码
}
override func loadView() {
// 模块化视图初始化
self.view = NSView(frame: NSRect(x: 0, y: 0, width: 200, height: 200))
// 添加更多子视图或控件
}
}
通过掌握 NSViewController
的这些常见 API 和基础技巧,了解其视图生命周期和使用场景,能够灵活高效地管理 macOS 应用的视图层次结构,更好地实现复杂和模块化的用户界面。