iosiphoneswiftxcodeuidocumentinteractioncontroller

Switching back to the app after Saving to iCloud Drive from UIDocumentInteractionController removes navigation hierarchy


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?


Solution

  • 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)

    enter image description here

    As you can see in the bottom left, the arrow will then provide options such as below, depending upon the document type

    enter image description here

    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.