在Swift 3中以编程方式创建一个没有XIB的NSViewController [英] Programmatically create an NSViewController without an XIB in Swift 3
问题描述
我试图在不使用Interface Builder的情况下制作macOS应用.我的项目已构建并运行,但是主视图控制器似乎并未加载其视图.即,不会调用viewDidLoad()
方法.我正在使用Xcode-beta 8.0 beta 6(8S201h).
I'm trying to make a macOS app without using Interface Builder. My project builds and runs, but my primary view controller doesn't seem to be loading its view. That is, the viewDidLoad()
method is not invoked. I'm using Xcode-beta 8.0 beta 6 (8S201h).
NSViewController
的Swift 3文档对此内容进行了说明:
The Swift 3 documentation for NSViewController
says this about the view
property:
如果在访问该属性时未设置其值,则视图控制器将调用
loadView()
方法.相应地,该方法从视图控制器的nibName
和nibBundle
属性标识的nib文件中设置视图.
If this property’s value is not already set when you access it, the view controller invokes the
loadView()
method. That method, in turn, sets the view from the nib file identified by the view controller’snibName
andnibBundle
properties.
如果您想直接设置视图控制器的视图,请在创建视图控制器后立即设置此属性的值.
If you want to set a view controller’s view directly, set this property’s value immediately after creating the view controller.
对于viewDidLoad
:
对于以编程方式创建的视图控制器,在
loadView()
方法完成后立即调用此方法.
For a view controller created programmatically, this method is called immediately after the
loadView()
method completes.
最后,对于isViewLoaded
:
视图控制器采用延迟加载其视图:将视图控制器加载到内存后,其
isViewLoaded
属性的值立即为false
.在loadView()
方法返回之后且恰好在系统调用viewDidLoad()
方法之前,该值将更改为true
.
A view controller employs lazy loading of its view: Immediately after a view controller is loaded into memory, the value of its
isViewLoaded
property isfalse
. The value changes totrue
after theloadView()
method returns and just before the system calls theviewDidLoad()
method.
因此文档使我相信这是可能的.
So the documentation leads me to believe it is possible.
我的项目如下:
.
├── main.swift
└── Classes
├── AppDelegate.swift
└── Controllers
└── PrimaryController.swift
main.swift
import Cocoa
let delegate = AppDelegate()
NSApplication.shared().delegate = delegate
NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
AppDelegate.swift
import Cocoa
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
let pc = PrimaryController(nibName: nil, bundle: nil)!
print(pc.isViewLoaded)
pc.view = NSView()
print(pc.isViewLoaded)
}
}
PrimaryController.swift
import Cocoa
class PrimaryController: NSViewController {
override func loadView() {
print("PrimaryController.loadView")
}
override func viewDidLoad() {
super.viewDidLoad()
print("PrimaryController.viewDidLoad")
}
}
使用上述内容构建和运行项目会产生以下控制台输出:
Building and running a project with the above yields this console output:
false
true
也就是说,视图将为控制器加载,但不会调用loadView
和viewDidLoad
方法.
That is, the view loads for the controller, but the loadView
and viewDidLoad
methods are never invoked.
我想念什么?
推荐答案
仔细阅读该文档对我们很有启发.具体来说:
A careful reading of the documentation is enlightening. Specifically:
如果访问时尚未设置此属性的值,则视图控制器将调用
loadView()
方法.
If this property’s value is not already set when you access it, the view controller invokes the
loadView()
method.
意思是,仅当尝试读取view
属性之前具有值时,才调用loadView()
.直接为属性分配值将绕过方法调用.
Meaning, loadView()
is only invoked when an attempt is made to read the view
property before the property has a value. Assigning a value to the property directly will bypass the method call.
因此,如果AppDelegate.applicationDidFinishLaunching(_:)
是这样写的:
So if AppDelegate.applicationDidFinishLaunching(_:)
is written like this:
let pc = PrimaryController(nibName: nil, bundle: nil)!
print(pc.isViewLoaded)
let x = pc.view // accessing the view property before it has a value
print(pc.isViewLoaded)
...然后loadView
将被系统调用以尝试加载视图:
...then loadView
will be invoked by the system to attempt to load the view:
false
PrimaryController.loadView
false
请注意,由于无法自动将视图与控制器关联(即笔尖为nil
且PrimaryController.xib
不存在),因此仍未调用viewDidLoad()
.完成此过程的正确方法是在PrimaryController.loadView()
中手动加载视图:
Note that viewDidLoad()
is still not invoked, since no view can be automatically associated with the controller (ie, the nib is nil
and PrimaryController.xib
doesn't exist). The correct way to complete the process is to manually load the view in PrimaryController.loadView()
:
print("PrimaryController.loadView")
view = NSView() // instantiate and bind a view to the controller
现在程序会提供所需的结果:
Now the program gives the desired result:
false
PrimaryController.loadView
PrimaryController.viewDidLoad
true
这篇关于在Swift 3中以编程方式创建一个没有XIB的NSViewController的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!