Implementing UIDocumentBrowserViewController
in an existing app. This vc, in iOS 11 is the root view controller, and tapping a file creates my doc, instantiates my view controller, and presents it inside a UINavigationController
. It all works, in that the files display, the proper document opens, the vc displays and works as expected. I had to add a left button to the nav bar to provide a way to close the doc/vc.
When I tap the "Done" button, the view controller closes and returns to the document browser. All of that is good.
The problem is that the view controller's memory isn't releasing (and the domino effect of document memory, etc then not releasing). In the iOS 10 side of things, with a UICollectionViewController
embedded in a UINavigationController
as the initial vc, but the doc and the display vc identical code for iOS 10 & 11, all memory releases. I've studied How to correctly dismiss a UINavigationController that's presented as a modal? and related posts, tried dozens of alternatives, and am just not seeing what I'm missing. Instruments isn't showing any memory leaks, though I see document objects in memory after dismissing the view controller. The log shows that the vc's viewWillDisappear
is being called at the proper time.
I appreciate any insights into why the vc memory isn't being released (deinit()
not being called).
Thank you.
@available(iOS 11.0, *)
class DocumentBrowserViewController: UIDocumentBrowserViewController, UIDocumentBrowserViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
allowsDocumentCreation = true
allowsPickingMultipleItems = false
}
// MARK: Document Presentation
func returnToDocumentBrowser(sender: UIBarButtonItem) {
print("returnToDocumentBrowser")
if let controller = self.presentedViewController as? UINavigationController {
controller.dismiss(animated: true, completion: nil)
}
}
func presentDocument(at documentURL: URL) {
print("present document")
let doc = MyDocument(fileURL: documentURL)
doc.open(completionHandler: { (success) in
if (success) {
print("open succeeded")
DispatchQueue.main.async {
let myController = self.storyboard!.instantiateViewController(withIdentifier: "my controller") as! MyViewController
myController.navigationItem.setLeftBarButton(UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.done, target: self, action: #selector(self.returnToDocumentBrowser(sender:))), animated: false)
myController.doc = doc
let navigationController = UINavigationController(rootViewController: myController)
self.present(navigationController, animated: true, completion: nil)
}
} else {
print("open failed")
}
})
}
}
The navigation stack seems at the heart of this. In the iOS 10 version, a collection view controller is the root view controller and is embedded in a navigation controller via storyboard.
In the iOS 11 version, the document browser view controller is the root view controller and cannot be embedded in a navigation controller. When I presented in the original code, my document view controller became the navigation stack's root view controller, and that cannot be popped, for example.
So I figured that maybe the navigation controller needed a different root view controller to mimic the prior behavior as much as possible and require the fewest code changes.
So I changed
to
This nav controller setup added a back button, meaning I didn't have to add a back button, and that handled popping the view controller automatically. As a result, I only needed to dismiss the nav controller, since it wasn't the app's root vc.
Finally, for the comment that the delegate should be declared weak, that's Apple's doing, and I just use it as provided. I'm not sure what affect that's having on things.