Отклонить 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
Ответы
Ответ 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")
})
})
}
Это работает для вашего случая.