簡體   English   中英

在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)。

NSViewController的Swift 3文檔說明了view屬性:

如果在訪問它時尚未設置此屬性的值,則視圖控制器將調用loadView()方法。 反過來,該方法從視圖控制器的nibNamenibBundle屬性標識的nib文件中設置視圖。

如果要直接設置視圖控制器的視圖,請在創建視圖控制器后立即設置此屬性的值。

對於viewDidLoad

對於以編程方式創建的視圖控制器,在loadView()方法完成后立即調用此方法。

最后,對於isViewLoaded

視圖控制器使用其視圖的延遲加載:在視圖控制器加載到內存后,其isViewLoaded屬性的值isViewLoadedfalse loadView()方法返回之后且在系統調用viewDidLoad()方法之前,該值將更改為true

所以文檔讓我相信它是可能的。


我的項目看起來像這樣:

 .
 ├── 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")
    }
}

使用上述方法構建和運行項目會產生此控制台輸出:

false
true

也就是說,視圖會加載控制器,但永遠不會調用loadViewviewDidLoad方法。

我錯過了什么?

仔細閱讀文檔是有啟發性的。 特別:

如果訪問它時尚未設置此屬性的值則視圖控制器將調用loadView()方法。

意思是,只有在屬性具有值之前嘗試讀取view屬性時,才會調用loadView() 直接為屬性賦值將繞過方法調用。

所以,如果AppDelegate.applicationDidFinishLaunching(_:)寫成如下:

    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以嘗試加載視圖:

false
PrimaryController.loadView
false

請注意,仍未調用viewDidLoad() ,因為沒有視圖可以自動與控制器關聯(即,nib為nilPrimaryController.xib不存在)。 完成該過程的正確方法是在PrimaryController.loadView()手動加載視圖:

print("PrimaryController.loadView")
view = NSView() // instantiate and bind a view to the controller

現在該程序提供了所需的結果:

false
PrimaryController.loadView
PrimaryController.viewDidLoad
true

從代碼生成ViewController的最小設置(Swift 4.1)

class WelcomeViewController: NSViewController {

   private lazy var contentView = MyCustomClassOrJustNSView()

   override func loadView() {
      view = contentView
   }

   init() {
      super.init(nibName: nil, bundle: nil)
   }

   required init?(coder: NSCoder) {
      fatalError()
   }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM