如何以编程方式在 NavigationController 链中重用 ViewController

How to reuse a ViewController in NavigationController chain programmatically

我今天将 google 驱动器 api 集成到我的应用程序后才意识到这个问题。如下图所示,tableView 中有一堆嵌套的文件夹。

在UINavigationController下面,所以一般我会做一个pushView navigationController?.pushViewController(vc, animated: true) 来打开一个新的ViewController,但不知道会是多少层,那就有点游戏结束。

根据我的经验,gif 图像只是在同一 ViewController 中刷新数据源,尽管它看起来像 pushView 操作。也许它添加了一些动画,让它像打开一个新的 ViewController 并在按下后退导航按钮时记录以前的数据源(文件夹)。

我的问题是 属性 在现实世界的应用程序中处理它的方法是什么?我的意思是许多应用程序将面临相同的情况。

在 Github 中查看 google 驱动项目后,我得到了解决方案。

他们只是递归地重新打开viewController本身来解决这个问题。虽然它会创建许多共存的 viewController 个实例,但它很耗内存,但我没有找到另一种方法来做到这一点。

经过几次测试,我打开了 viewController 的 20 深度,我的应用程序没有崩溃,从调试内存图,我可以看到打开一个 VC 只需要一个有点记忆力,不错!

下面是我的代码,希望它能帮助遇到这个特殊问题的人。

我的递归 GoogleDriveVC

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(tableView)
        tableView.dataSource = self
        tableView.delegate = self
        tableView.rowHeight = 52
        tableView.frame = view.bounds
        
        if title == nil { title = "Google Drive" }
        
        loadData()
    }
    
    func loadData() {
        listAudioFilesAndFolders()
    }
    
    func listAudioFilesAndFolders() {
        showSpinner()
        // for root folder
        var id = "root"
        if let folderID = self.folderID {
            id = folderID
        }
        
        DispatchQueue.global(qos: .background).async { [weak self] in
            self?.googleAPIs?.listFiles(id, onCompleted: { files, error in
                guard error == nil, files != nil else {
                    print("Err: \(String(describing: error))")
                    return
                }
                
                // filter the files before passing it.
                self?.audioFilesAndFolders = files?.filter { [=10=].mimeType == "audio/mpeg" || [=10=].mimeType == "application/vnd.google-apps.folder"}
                print("load data in google drive's current level complete")
                DispatchQueue.main.async {
                    self?.tableView.reloadData()
                    self?.removeSpinner()
                }
            })
        }
    }

extension GoogleDriveFilesViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        
        guard let files = self.audioFilesAndFolders else { return }
        let file = files[indexPath.row]
        // open a new VC when file type is 'folder'
        if file.mimeType == "application/vnd.google-apps.folder" {
            let vc = GoogleDriveFilesViewController()
            vc.folderID = file.identifier
            vc.title = file.name
            vc.modelController = self.modelController
            navigationController?.pushViewController(vc, animated: true)
        }
    }
}

google api

    public func listFiles(_ folderID: String, onCompleted: @escaping ([GTLRDrive_File]?, Error?) -> ()) {
        let query = GTLRDriveQuery_FilesList.query()
        query.pageSize = 100
        query.q = "'\(folderID)' in parents"
//        self.service.shouldFetchNextPages = true
        self.service.executeQuery(query) { (ticket, results, error) in
            onCompleted((results as? GTLRDrive_FileList)?.files, error)
        }
    }