I am using UIDocumentInteractionController to save the document at specified URL to iCloud Drive, but the problem is that when I switch back to the app after saving/cancel from iCloud, my original view controller is no longer present, the entire navigation hierarchy is removed and the root view controller is shown.
I am presenting the options in the menu from a view controller that is presented view controller.
extension ADDTextChatViewController: AddReceiverFileDelegate {
func downloadTapped(url: String?, cell: AddReceiverTableViewCell) {
guard let urlString = url else {return}
shareAction(withURLString: urlString, cell: cell)
}
}
extension ADDTextChatViewController {
func share(url: URL, cell: AddReceiverTableViewCell) {
documentInteractionController.url = url
documentInteractionController.uti = url.typeIdentifier ?? "public.data, public.content"
documentInteractionController.name = url.localizedName ?? url.lastPathComponent
documentInteractionController.presentOptionsMenu(from: cell.btnDownload.frame, in: view, animated: true)
}
func shareAction(withURLString: String, cell: AddReceiverTableViewCell) {
guard let url = URL(string: withURLString) else { return }
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else { return }
let tmpURL = FileManager.default.temporaryDirectory
.appendingPathComponent(response?.suggestedFilename ?? "fileName.png")
do {
try data.write(to: tmpURL)
} catch { print(error) }
DispatchQueue.main.async {
self.share(url: tmpURL, cell: cell)
}
}.resume()
}
}
extension URL {
var typeIdentifier: String? {
return (try? resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier
}
var localizedName: String? {
return (try? resourceValues(forKeys: [.localizedNameKey]))?.localizedName
}
}
What shall I do in order to remain on the same view controller from which I called this method, after switching back from iCloud?
So it turns out that in order to maintain the navigation stack, you need to pass the navigation controller into the UIDocumentInteractionControllerDelegate
method documentInteractionControllerViewControllerForPreview
.
In the document for this delegate method it is stated that If presenting atop a navigation stack, provide the navigation controller in order to animate in a manner consistent with the rest of the platform
So here's what my code looks like now, after implementing this delegate method.
extension ADDTextChatViewController: UIDocumentInteractionControllerDelegate {
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
guard let navVC = self.navigationController else {
return self
}
return navVC
}
}
And I added
documentInteractionController.presentPreview(animated: true)
instead of
documentInteractionController.presentOptionsMenu(from: view.frame, in: view, animated: true)
which will first show the preview of the document like this (Please see that, this preview will be pushed from my ADDTextChatViewController
)
As you can see in the bottom left, the arrow will then provide options such as below, depending upon the document type
So now when I switch back to my application after transitioning to iCloud Drive/ any of the options in the action sheet, my navigation stack is not removed.
I hope this helps someone in future as well.