简体   繁体   中英

Deallocate current VC and push a different VC

Short explanation of the issue:

I have a screen in my app which simulates a room with multiple users in it, and the user can click 'next room' and it will push onto the navigation stack another instance of the room view controller. This is a memory usage issue for now, because I simply push another instance onto the stack, which leaves the previous room (which is irrelevant) still allocated in memory as it is still in the navigation stack, and it consumes a lot of memory when there are a lot of chat room instances allocated (for example if a user moves to a lot of different rooms).

The navigation stack after a user clicks 'next room':
func cleanUpNavigationStack() {
   guard let previousRoomVCIndex = self.navigationController?.viewControllers.firstIndex(where: 
   { $0 is RoomViewController }) else {return}
   self.navigationController?.viewControllers.remove(at: previousRoomVCIndex)
}

Index 3 should be deallocated after index 4 has been appended to the stack, I do not need index 3 which is the previous room.


What I've tried:

I've implemented a method to clean up the navigation stack after a new 'RoomViewController' has been appended to the navigation stack.
 func cleanUpNavigationStack() { guard let previousRoomVCIndex = self.navigationController?.viewControllers.firstIndex(where: { $0 is RoomViewController }) else {return} self.navigationController?.viewControllers.remove(at: previousRoomVCIndex) }

I call this method right after pushing the new RoomViewController onto the navigation stack. So what I've expected to happen is:
1 -> Pushing a new RoomViewController
2 -> Now the navigation stack contains 2 RoomViewControllers, the last one which is the relevant one, and the first one which is the previous irrelevant room.
3 -> I remove the previous irrelevant room from my navigation stack.
4 -> It is being deallocated from memory as well, and if I pop one VC back, it should take me to the LoadingViewController.

But after calling print(navigationController?.viewControllers) when I am done cleaning up the navigation stack, I still see the previous RoomViewController, so the removal didn't work for some reason.
What could be the reason for this? and how should I approach it?

My main goal at the end is to deallocate the current RoomVC when pushing a new RoomVC.

You remove screen from array (of Nav Stack), that means this array doesn't hold reference to this screen anymore. But UINavigationController still holds a ref childVC (this screen), UIWindow's subview still holds a ref to this screen's view. It can not be deallocated. That is why we need to call navigationController.pop...

The best UX is showing the room list as a Horizontal Page View.

You will need to make a PageItem (can be UICollectionViewCell) and then setup like normal UICollectionView logic.

Or you can use this trick:

Code in RoomListScreen.swift

import UIKit

class RoomListScreen: UIViewController {

    @IBOutlet weak var buttonOpenRoom: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func actionDisplayRoomDetail(_ sender: Any) {
        let roomScreen = RoomScreen()
        roomScreen.onOpenNextRoom = { [unowned self] in
            self.handleOnOpenNextRoom()
        }
        self.navigationController?.pushViewController(roomScreen, animated: true)
    }
    
    func handleOnOpenNextRoom() {
        let roomScreen = RoomScreen()
        roomScreen.onOpenNextRoom = { [unowned self] in
            self.handleOnOpenNextRoom()
        }

        // pop current screen (RoomScreen) without animation -> slient popping.
        self.navigationController?.popViewController(animated: false)

        // If you want to have a nature animation like push new screen, pass true to animated: ..., but the RoomListScreen be visible in 0.2-0.3 seconds, so, it is not good UI/UX. It is acceptable but still confuse user sometime.
        self.navigationController?.pushViewController(roomScreen, animated: false)
    }
}

Code in RoomScreen.swift

import UIKit

class RoomScreen: UIViewController {
    @IBOutlet weak var buttonNextRoom: UIButton!
    
    var onOpenNextRoom: (() -> Void)?
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func actionClickNextRoom(_ sender: Any) {
        self.onOpenNextRoom?()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print(self.navigationController?.viewControllers ?? [])
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM