В моем AppDelegate.swift
есть следующий код Swift 5:
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
static let mainWindowNibName = "MainWindow"
/// The main MainWindowController created when the app launches.
var mainController: MainWindowController!
/// Any additional windows opened by the user.
var createdWindowControllers: [MainWindowController] = []
@objc func newWindow(_ sender: Any) {
let controller = MainWindowController(windowNibName: AppDelegate.mainWindowNibName)
controller.showWindow(self)
self.createdWindowControllers.append(controller)
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
let controller = MainWindowController(windowNibName: AppDelegate.mainWindowNibName)
controller.window!.makeKeyAndOrderFront(self)
self.mainController = controller
}
func applicationWillTerminate(_ aNotification: Notification) {
}
}
Это стандартный NSApplicationDelegate
, который при запуске приложения открывает окно «по умолчанию» с использованием подкласса NSWindowController
с пером и присваивает его свойству класса, чтобы сохранить значение.Для обработки дополнительно созданных окон пользовательское событие newWindow:
отправляется с помощью NSMenuItem
, привязанного к N + N, который создает новое окно и добавляет его в массив MainWindowController
s, чтобы сохранить их.
Это хорошо работает, чтобы поддерживать работоспособность контроллеров, но они никогда не выпускаются;когда пользователь закрывает дополнительно открытые окна, они остаются в createdWindowControllers
, никогда не освобождаясь через ARC.Эти NSWindowController
и содержащиеся NSViewController
выделяют много памяти для выполнения своей задачи (загрузка большого количества файлов из базы данных и их отображение), поэтому я хотел бы освободить эти контроллеры, когда пользователь их закрывает.
Чтобы решить эту проблему, я создал «диспетчер ссылок контроллера окон» (метко названный WindowControllerManager
):
import Cocoa
class WindowControllerManager<T: NSWindowController>: NSObject, NSWindowDelegate {
var windows: [T] = []
func add(_ controller: T) {
windows.append(controller)
}
func windowWillClose(_ notification: Notification) {
let window = notification.object as! NSWindow
let controller = window.windowController as! T
if let index = self.windows.firstIndex(of: controller) {
self.windows.remove(at: index)
} else {
NSLog("WindowReferenceManager: Cannot find \(controller) (window: \(window))")
}
}
}
Когда подклассы NSWindowController
добавляются в этот вспомогательный класс, windowWillClose:
событие прослушивается и вызывает удаление окна из массива контроллеров при их закрытии, что приводит к их освобождению.
Я использую это в моем текущем файле AppDelegate.swift
, и оно работает:
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
static let mainWindowNibName = "MainWindow"
var windowReferenceManager: WindowControllerManager = WindowControllerManager()
@objc func newWindow(_ sender: Any) {
let controller = MainWindowController(windowNibName: AppDelegate.mainWindowNibName)
controller.showWindow(self)
controller.window!.delegate = self.windowReferenceManager
self.windowReferenceManager.add(controller)
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
let controller = MainWindowController(windowNibName: AppDelegate.mainWindowNibName)
controller.window!.makeKeyAndOrderFront(self)
controller.window!.delegate = self.windowReferenceManager
self.windowReferenceManager.add(controller)
}
func applicationWillTerminate(_ aNotification: Notification) {
}
}
Однако я не думаю, что это очень элегантное решение.Есть ли лучший способ сделать это, не включающий создание вспомогательного класса, подобного этому?
Я относительно новичок в Cocoa и AppKit;Я даже не уверен, правильно ли я создаю окна.