Search code examples
iosswiftgpx

Importing a GPX file results in an error that the text encoding of its contents can’t be determined


I'm letting users import a GPX file through the following method:

let documentPickerController = UIDocumentPickerViewController(documentTypes: ["public.item"], in: .import)
documentPickerController.allowsMultipleSelection = false
documentPickerController.delegate = self
self.present(documentPickerController, animated: true, completion: nil)

And parsing the selected file as following:

func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
    let firstFileURL = urls[0]
    var outputFileURL: URL? = nil

    let coordinator = NSFileCoordinator()
    var error: NSError? = nil
    coordinator.coordinate(readingItemAt: firstFileURL, options: [], error: &error) { (externalFileURL) -> Void in
        var tempURL = URL(fileURLWithPath: NSTemporaryDirectory())
        tempURL.appendPathComponent(externalFileURL.lastPathComponent)
        
        do {
            if FileManager.default.fileExists(atPath: tempURL.path) {
                try FileManager.default.removeItem(atPath: tempURL.path)
            }
            
            try FileManager.default.copyItem(atPath: externalFileURL.path, toPath: tempURL.path)
            outputFileURL = tempURL
        } catch {
            print("File operation error: " + error.localizedDescription)
        }
    }
    
    navigationController?.dismiss(animated: true, completion: nil)

    guard let path = outputFileURL?.path else { return }
    
    do {
        let content = try String(contentsOfFile: path) // error here
        let data = content.data(using: .utf8)
        let parser = XMLParser.init(data: data!)
    } catch {
        print(error)
    }
}

But, I'm getting the following error message:

couldn’t be opened because the text encoding of its contents can’t be determined.

I thought maybe it was the way I was importing the files so I tried changing public.item to following:

let types = UTType.types(tag: "gpx", tagClass: UTTagClass.filenameExtension, conformingTo: nil)
let documentPickerController = UIDocumentPickerViewController(documentTypes: types, in: .import)
documentPickerController.allowsMultipleSelection = false
documentPickerController.delegate = self
self.present(documentPickerController, animated: true, completion: nil)

and modifying the info.plist as explained in this article.

But then, none of the GPX files become selectable and turn grey from within the document picker.


Solution

  • You're absolutely right. This expression is just wrong:

    String(contentsOfFile: path)
    

    You could specify the encoding by adding an encoding: parameter.

    https://developer.apple.com/documentation/swift/string/init(contentsoffile:encoding:)

    But don't. Don't use String(contentsOfFile:) at all. Don't use file paths at all. Use file URLs. Given a file URL, read from it with String(contentsOf:encoding:).

    https://developer.apple.com/documentation/swift/string/init(contentsof:encoding:)