Подтвердить что ты не робот

Отклонить ViewController после перехода к освобождению памяти

Я хочу освободить память моего ViewController, используемого после отклонения. Я использую следующий код для представления нового ViewController и отклонения старого:

let sB: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newVC: UIViewController = sB.instantiateViewController(withIdentifier: "MyVC")
self.present(newVC, animated: true, completion: { x in
    oldVC.dismiss(animated: false, completion: { _ in //oldVC: variable keeping track of currently visible view controller
        print("done")
    })
})

Этот код успешно представляет newVC и печатает done после отклонения oldVC. Тем не менее, моя память по-прежнему остается такой же высокой, как при oldVC на экране.
Что я делаю неправильно?

FYI

  • Я использую ENSwiftSideMenu
    • Так как я не работал над ним другим способом, все мои ViewControllers являются подклассом ENSideMenuNavigationController
  • Я получаю консольные предупреждения об отдельных видах и представлениях, которые не находятся в иерархии окон.
  • для всех ViewControllers, как presentingViewController, так и presentedViewController являются nil
4b9b3361

Ответ 1

Проверьте следующие проблемы:

  • Вы должны отклонить старый ViewController до того, как появился новый ViewController, или вы будете отклонять новый в одно и то же время.
  • Быстрое использование ARC для управления памятью. Старый VC не выпущен, так как некоторые объекты имеют для него сильную ссылку. Сделайте пример, у меня есть ViewController с переменной tableView. TableView будет выпущен при выпуске ViewController. Но в то же время, если вы связали его с другим ViewController, который не был выпущен, tableView не будет выпущен, хотя предыдущий ViewController будет выпущен.

Решение:

  • Представьте UINavigationController и с помощью setViewControllers, чтобы управлять переходом ваших ViewControllers.
  • Удалите ненужную ссылку oldVC

Если вы действительно не понимаете. Вы можете выполнить поиск:

  • ARC
  • Переход UIViewController

Ответ 2

Ваш oldVC не будет освобожден, так как ваш newVC (и любой UIViewController) по умолчанию по-прежнему ссылается на свой presentingViewController - контроллер, который его представил. Если это не так, вы никогда не сможете безопасно отклонить ваш newVC, не нарушая иерархию представлений.

Что касается вашей конкретной проблемы, чтобы освободить старый контроллер представлений, я бы предложил сначала отклонить oldVC, а затем отобразить ваш newVC из другого ViewController ранее в стеке (может быть UIApplication shared().keyWindow?.rootViewController)

Ответ 3

У меня была та же проблема для UINavigationController push/pop. @spassas прав насчет сильной ссылки, из-за которой ваш newVC не освобождается. Вы должны внимательно посмотреть на newVC.

В моем случае (написанном в Objective-C) был еще один контроллер представления, на который ссылается как частное свойство контроллера толкаемого представления (ваш newVC):

EventActionSheetViewController* actionSheet;

То, что actionSheet имело сильную ссылку на контроллер толкаемого представления (newVC) в качестве его делегата:

@property (nonatomic) id<EventActionSheetDelegate> delegate;

Я проверяю память своего приложения и обнаружил, что контроллер push-view не был освобожден после того, как его выталкивает контроллер навигации. Через несколько часов я изменил сильную ссылку на слабых, и это получилось:

@property (nonatomic, weak) id<EventActionSheetDelegate> delegate;

Проблема заключалась в том, что мой нажатый контроллер представления и его EvenetActionSheetViewController имели сильные ссылки друг на друга и каким-то образом не позволяли друг другу освобождаться.

Я рекомендую вам проверить, имеет ли ваш newVC аналогичные сильные контуры ссылок и по возможности меняет их на слабые места. В Swift используйте weak let или weak var вместо let/var. Надеюсь, это поможет вам найти ошибку.

Ответ 4

Попробуйте заменить код следующим образом:

    let appDel = UIApplication.shared.delegate as! AppDelegate
    let sB: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    let newVC = sB.instantiateViewController(withIdentifier: "MyVC")
    appDel.window?.rootViewController = newVC
    appDel.window?.makeKeyAndVisible()

Надеюсь, что это сработает!

ИЗМЕНИТЬ: Вы также можете проверить, что старый контроллер просмотра деинициализирован, добавив следующий код ко всем контроллерам просмотра:

    deinit {
        debugPrint("Name_Of_View_Controller deinitialized...")
    }

ИЗМЕНИТЬ 2:

Если вы хотите сохранить поток представления в контроллерах представления, и вы хотите только отклонить последний контроллер представления, т.е.

В переходе: masterVC → oldVC → newVC

И после перехода с oldVC на newVC вы хотите вернуться к masterVC, освободив память от oldVC. Вы можете передать ссылку masterVC на oldVC и достичь того, что хотите:

if(masterVC != nil) {
         oldVC.dismiss(animated: false, completion: {
            let sB: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
            let newVC = sB.instantiateViewController(withIdentifier: "vc2")
            self.masterVC!.present(newVC, animated: false, completion: {
                print("done")
            })
        })
}

Это работает для вашего случая.