如何以编程方式在 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)
}
}
我今天将 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)
}
}