Освободить контроллеры представления в контроллере навигации, которые имеют ссылку на себя

Скажем, у меня есть контроллеры представления 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:

У меня были подобные проблемы, я советую вам взглянуть на эту ссылку: Как я могу управлять и освобождать память через ViewControllers

Другие вопросы по тегам