简体   繁体   English

释放当前 VC 并推送不同的 VC

[英]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. 我的应用程序中有一个屏幕,它模拟一个有多个用户的房间,用户可以单击“下一个房间”,它将把房间视图 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). 这是一个 memory 使用问题,因为我只是将另一个实例推入堆栈,这使得之前的空间(无关紧要)仍然分配在 memory 中,因为它仍在导航堆栈中,并且它消耗了大量的 ZCD6917ZBFD6 时分配了很多聊天室实例(例如,如果用户移动到很多不同的房间)。

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.索引 3 应该在索引 4 附加到堆栈后被释放,我不需要索引 3,它是前一个房间。


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. 在将新的“RoomViewController”附加到导航堆栈后,我实现了一种清理导航堆栈的方法。
 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.我在将新的 RoomViewController 推送到导航堆栈后立即调用此方法。 So what I've expected to happen is:所以我期望发生的是:
1 -> Pushing a new RoomViewController 1 -> 推送一个新的 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. 2 -> 现在导航堆栈包含 2 个 RoomViewController,最后一个是相关的,第一个是前一个不相关的房间。
3 -> I remove the previous irrelevant room from my navigation stack. 3 -> 我从导航堆栈中删除了以前不相关的房间。
4 -> It is being deallocated from memory as well, and if I pop one VC back, it should take me to the LoadingViewController. 4 -> 它也从 memory 中释放,如果我弹出一个 VC,它应该带我到 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.但是在我清理完导航堆栈后调用print(navigationController?.viewControllers)后,我仍然看到以前的 RoomViewController,所以由于某种原因,删除没有奏效。
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.最后我的主要目标是在推送新的 RoomVC 时释放当前的 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.但是UINavigationController仍然持有一个 ref childVC (这个屏幕), UIWindow's subview仍然持有这个屏幕视图的一个 ref。 It can not be deallocated.它不能被释放。 That is why we need to call navigationController.pop...这就是为什么我们需要调用navigationController.pop...

The best UX is showing the room list as a Horizontal Page View.最好的 UX 将房间列表显示为水平页面视图。

You will need to make a PageItem (can be UICollectionViewCell) and then setup like normal UICollectionView logic.您需要创建一个 PageItem(可以是 UICollectionViewCell),然后像普通的 UICollectionView 逻辑一样进行设置。

Or you can use this trick:或者你可以使用这个技巧:

Code in RoomListScreen.swift 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 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 ?? [])
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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