#swift #macos #cocoa #delegation #nsviewcontroller
#swift #macos #cocoa #делегирование #nsviewcontroller
Вопрос:
У меня здесь странная ситуация, которая почти наверняка связана с тем, что я новичок в разработке macOS и мне не хватает некоторых базовых знаний.
У меня есть модальный лист, который я отображаю программно. (Я не использую переход к раскадровке, потому что он должен быть результатом проверки, и пока я не видел способа запустить переход программно — это дополнительный вопрос здесь, если у кого-нибудь есть совет)
Вот как я это делаю:
searchVC = NSStoryboard(name: "Main", bundle: nil).instantiateController(withIdentifier: "SearchSceneIdentifier") as? SearchViewController
if searchVC != nil {
searchVC!.searchTerm = searchTextField.stringValue
self.presentAsSheet(searchVC!)
}
Это красиво отображает таблицу и позволяет мне взаимодействовать с ней. В нем я использую класс, у которого есть делегат, чтобы возвращать асинхронные поисковые запросы.
Где это становится странным, так это когда я вызываю
self.view.window!.close()
изнутри контроллера представления я не думаю, что контроллер представления освобождается. Похоже, это связано с тем, что делегат все еще подключен к нему, даже если объект, у которого есть этот делегат, находится в области действия самого контроллера представления. Похоже, что этот делегат удерживает контроллер представления в памяти.
Я обошел это, сделав это перед закрытием окна:
search.delegate = nil
Но это не очень хорошее решение для других контроллеров просмотра, у которых такая же проблема, потому что они находятся внутри Windows, и я не хочу перехватывать закрытие окна, а затем отправлять какое-либо уведомление каждому, чтобы свести к нулю их делегатов.
Другой подход, который также кажется неправильным, заключается в том, что я сохраняю ссылку на эти окна в делегате приложения и обнуляю ее оттуда.
Все это кажется неприятным решением проблемы освобождения, и я надеюсь, что есть более чистый способ сделать это. В Objective-C подсчет ссылок всегда был проблемой, но существовали шаблоны для их точной обработки.
Приветствуются любые советы.
Комментарии:
1. В документации
presentAsSheet(_:)
говорится: «Чтобы закрыть лист, вызовите метод dismiss(_:) для self (представляющий контроллер представления)»..2. Действительно, это так, спасибо. Но выполнение этого без установки для делегата значения nil приводит к тому, что контроллер представления остается выделенным и продолжает получать вызовы метода делегирования.
3. Является ли делегат владельцем ссылки на лист? Или есть что-то еще, содержащее надежную ссылку на лист?
4. Из моего тестирования кажется, что делегат — это единственное, что имеет ссылку. Однако вы используете слово «сильный» — можно ли решить эту проблему, сделав делегат слабой переменной в своем классе? В настоящее время он определен как public var delegate: SearchDelegate?
5. ваше свойство делегата должно быть слабым. Это обычный сценарий. Свойства делегата почти всегда следует объявлять слабыми из-за подобных проблем с циклом сохранения.
Ответ №1:
Я обновил все свои делегаты до weak var
, и это решило все мои проблемы с освобождением.