Освободить контроллеры представления в контроллере навигации, которые имеют ссылку на себя
Скажем, у меня есть контроллеры представления A, B, C, D & E, все они встроены в контроллер навигации. В контроллере представления B у меня есть собственный объект UIImageView. В C у меня есть пользовательский объект UITextfield. Оба пользовательских класса имеют ссылку на контроллер представления по разным причинам, таким как я должен выполнять такие вещи, как segue, когда пользователь нажимает на изображение. Для этого у меня есть это внутри каждого файла пользовательского класса:
var controller: UIViewController?
И затем внутри каждого контроллера представления, внутри viewDidLoad, я устанавливаю эту переменную на себя, и все работает как положено (переходы при нажатии и т. Д.)
У меня есть переход от E обратно к A. Однако я заметил, что из-за этих пользовательских объектов в контроллерах представления B & C оба не были освобождены из-за цикла сохранения, вызванного наличием этой ссылки на контроллер представления. Я исправил проблему, установив переменную контроллера равной nil при переходе от segue, однако это создает проблему, заключающуюся в том, что, если пользователь возвращается (высвечивает текущий контроллер представления), потому что я устанавливаю переменную контроллера равной nil при переходе, ничего не работает (это не будет снова, потому что контроллер var = nil). Я думал, что мог бы это исправить, добавив код viewWillAppear следующим образом:
override func viewWillAppear(_ animated: Bool) {
usernameTextField.controller = self
passwordTextField.controller = self
}
Потому что я читал, что viewWillAppear будет вызываться каждый раз, когда viewcontroller появляется в представлении. Это не решило проблему.
Есть идеи, как это сделать? Как я могу установить контроллеры на ноль во время раскрутки, может быть...?
3 ответа
Как уже говорилось в других ответах, вам нужно сделать это слабой ссылкой, подобной этой:
weak var controller: UIViewControler?
Однако я бы пошел дальше и сказал, что вы не должны хранить ссылку на UIViewController внутри какого-либо объекта на основе UIView (UIImageView, UITextField и т. Д.). UIViews не должен знать что-либо об их UIViewControllers.
Вместо этого вы должны использовать шаблон делегирования. Это основной пример:
1) Создайте протокол для пользовательского UIImageField следующим образом:
protocol MyImageFieldProtocol: class {
func imageTapped()
}
2) Затем добавьте делегата следующим образом:
weak var delegate: MyImageFieldProtocol?
3) Затем ваш UIViewController соответствует протоколу следующим образом:
class MyViewController: UIViewController, MyImageFieldProtocol {
}
4) Где-то внутри контроллера представления (viewDidLoad обычно является хорошим местом, где вы назначаете контроллер представления делегату представлений изображения следующим образом:
func viewDidLoad {
super.viewDidLoad()
myImageView.delegate = self
}
5) Затем добавьте функцию для ответа на действие протокола в контроллер представления следующим образом:
func imageTapped {
self.performSegue(withIdentifier: "MySegue", sender: nil)
}
var controller: UIViewController?
должен быть weak
ссылка. Как это:
weak var controller: UIViewController?
Чтобы узнать больше об этом, прочитайте о разрешении сильных циклов ссылок между экземплярами классов в документации Swift.
Вы должны использовать слабые ссылки, когда вы держите некоторые ViewControllers
weak var controller: UIviewControler?
Вы должны проверить все ссылки, чтобы сохранить цикл, и ссылки в Swift:
- https://krakendev.io/blog/weak-and-unowned-references-in-swift
- https://medium.com/@chris_dus/strong-weak-unowned-reference-counting-in-swift-5813fa454f30
У меня были подобные проблемы, я советую вам взглянуть на эту ссылку: Как я могу управлять и освобождать память через ViewControllers