Last active
April 11, 2022 11:09
-
-
Save aheze/dbc7f9b452e4f86f2d8fe278b3c5001f to your computer and use it in GitHub Desktop.
UIDocumentPickerViewController example in Swift 5. Bug fixed version of this article: https://medium.com/flawless-app-stories/a-swifty-way-to-pick-documents-59cad1988a8a
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// DocumentPicker.swift | |
import UIKit | |
import MobileCoreServices | |
protocol DocumentDelegate: class { | |
func didPickDocument(document: Document?) | |
} | |
class Document: UIDocument { | |
var data: Data? | |
override func contents(forType typeName: String) throws -> Any { | |
guard let data = data else { return Data() } | |
return try NSKeyedArchiver.archivedData(withRootObject:data, | |
requiringSecureCoding: true) | |
} | |
override func load(fromContents contents: Any, ofType typeName: | |
String?) throws { | |
guard let data = contents as? Data else { return } | |
self.data = data | |
} | |
} | |
open class DocumentPicker: NSObject { | |
private var pickerController: UIDocumentPickerViewController? | |
private weak var presentationController: UIViewController? | |
private weak var delegate: DocumentDelegate? | |
private var pickedDocument: Document? | |
init(presentationController: UIViewController, delegate: DocumentDelegate) { | |
super.init() | |
self.presentationController = presentationController | |
self.delegate = delegate | |
} | |
public func displayPicker() { | |
/// pick movies and images | |
self.pickerController = UIDocumentPickerViewController(documentTypes: [kUTTypeMovie as String, kUTTypeImage as String], in: .import) | |
self.pickerController!.delegate = self | |
self.presentationController?.present(self.pickerController!, animated: true) | |
} | |
} | |
extension DocumentPicker: UIDocumentPickerDelegate { | |
/// delegate method, when the user selects a file | |
public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { | |
guard let url = urls.first else { | |
return | |
} | |
documentFromURL(pickedURL: url) | |
delegate?.didPickDocument(document: pickedDocument) | |
} | |
/// delegate method, when the user cancels | |
public func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { | |
delegate?.didPickDocument(document: nil) | |
} | |
private func documentFromURL(pickedURL: URL) { | |
/// start accessing the resource | |
let shouldStopAccessing = pickedURL.startAccessingSecurityScopedResource() | |
defer { | |
if shouldStopAccessing { | |
pickedURL.stopAccessingSecurityScopedResource() | |
} | |
} | |
NSFileCoordinator().coordinate(readingItemAt: pickedURL, error: NSErrorPointer.none) { (readURL) in | |
let document = Document(fileURL: readURL) | |
pickedDocument = document | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ViewController.swift | |
class ViewController: UIViewController, DocumentDelegate { | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
/// set up the document picker | |
documentPicker = DocumentPicker(presentationController: self, delegate: self) | |
} | |
/// callback from the document picker | |
func didPickDocument(document: Document?) { | |
if let pickedDoc = document { | |
let fileURL = pickedDoc.fileURL | |
/// do what you want with the file URL | |
} | |
} | |
} |
Hmm...
This works for me:
func didPickDocument(document: Document?) {
if let pickedDoc = document {
let fileURL = pickedDoc.fileURL
let data = try Data(contentsOf: fileURL)
}
}
Usage.swift
import UIKit
import MobileCoreServices
class ViewController: UIViewController, DocumentDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func actionButtonTapped(_ sender: Any) {
let documentPicker = DocumentPicker(presentationController: self, delegate: self)
documentPicker.displayPicker()
}
/// callback from the document picker
func didPickDocument(document: Document?) {
if let pickedDoc = document {
let fileURL = pickedDoc.fileURL
/// do what you want with the file URL
print(fileURL)
let data = try Data(contentsOf: fileURL)
}
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for sharing. However
data
inDocument
always returnsnil
. Can you share a fix for that?