Есть ли лучший способ сохранить NSWindowController при отпускании при закрытии окна? - PullRequest
0 голосов
/ 25 июня 2019

В моем 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;Я даже не уверен, правильно ли я создаю окна.

...