UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Looking for help: how to select and open an existing data file with a document browser?

Forums > SwiftUI

I've gotten pretty far with a SwiftUI 2 app that reads a file of strings (with a specific file name) that is in the bundle. I've been looking to change it to use a document browser so that a local file (with any name, extension .inp) can be used (or perhaps on iCloud) and have gotten confused...

SwiftUI 2 has new Doc Based App setup that includes a simple way to use a Document Group and edit a new document. I've changed the default from DocumentGroup(new document: ...) to DocumentGroup(viewing: ...) but a file that I'd like to choose is "greyed out" and it seems to only like files that were created with the DocumentGroup(new document: ...). In addition, I just want to get a browser to select a file; I don't think I need the @main file to set a scene for just this?

So I think I just need a way to retreve the path (url?) to a file, and then I can read it, etc., with similar logic to reading the file that has a spefific name that is in the bundle.

I'm surprised that I've not been able to find an example of something like this (or figure it out on my own...), but a pointer to an example would be welcomed!

3      

Since I posted this, I've made some progress, below, but now have a permissons issue that I'll describe.

First, based on the iOS 14 release notes, there is a new .fileImporter() now available. I also modified code from a post by Aaron Wright at https://medium.com/better-programming/importing-and-exporting-files-in-swiftui-719086ec712 to get to just the code for importing a file.

//  InputDocument.swift
//  ImportFileAndRead
//
//   based on: Aaron Wright's post:
//   https://medium.com/better-programming/importing-and-exporting-files-in-swiftui-719086ec712
//

import SwiftUI
import UniformTypeIdentifiers

struct InputDoument: FileDocument {

    static var readableContentTypes: [UTType] { [.plainText] }

    var input: String

    init(input: String) {
        self.input = input
    }

    init(configuration: FileDocumentReadConfiguration) throws {
        guard let data = configuration.file.regularFileContents,
              let string = String(data: data, encoding: .utf8)
        else {
            throw CocoaError(.fileReadCorruptFile)
        }
        input = string
    }

    func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
        return FileWrapper(regularFileWithContents: input.data(using: .utf8)!)
    }

}
//  ContentView.swift
//  Shared
//
//  Created on 9/26/20.
//

import SwiftUI

struct ContentView: View {

    @State private var document: InputDoument = InputDoument(input: "")
    @State private var isImporting: Bool = false

    var body: some View {
        HStack {
            Button(action: { isImporting = true}, label: {
                Text("Push to browse to location of data file")
            })
            Text(document.input)
        }
        .padding()
        .fileImporter(
            isPresented: $isImporting,
            allowedContentTypes: [.plainText],
            allowsMultipleSelection: false
        ) { result in
            do {
                guard let selectedFile: URL = try result.get().first else { return }
                guard let input = String(data: try Data(contentsOf: selectedFile), encoding: .utf8) else { return }
                document.input = input
            } catch {
                // Handle failure.
                print("Unable to read file contents")
                print(error.localizedDescription)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

This works great on the iPad simulator!

However, when I run it on an actual iPad device, I get the error: Unable to read file contents The file “xyz.inp” couldn’t be opened because you don’t have permission to view it.

This happens when I am trying a local file, or iCloud.

I've tried to muck about with the info.plist for documents and either don't know what I'm doing, or perhaps this is not the path forward...

3      

I'm having the same issue and no luck so far, I would be interested in any solutions you found.

3      

@jturo  

I am having the same issue on iPhone (file import working on Simulator, not on physical device). Curious to hear if anyone found a solution to this.

3      

I had the same problem and think I may have found a Solution:

You have to call startAccessingSecurityScopedResource() on the URL before reading the Files content.

.fileImporter(
            isPresented: $isImporting,
            allowedContentTypes: [.plainText],
            allowsMultipleSelection: false
        ) { result in
            do {
                guard let selectedFile: URL = try result.get().first else { return }
                if selectedFile.startAccessingSecurityScopedResource() {
                    guard let input = String(data: try Data(contentsOf: selectedFile), encoding: .utf8) else { return }
                    defer { selectedFile.stopAccessingSecurityScopedResource() }
                    document.input = input
                } else {
                    // Handle denied access
                }
            } catch {
                // Handle failure.
                print("Unable to read file contents")
                print(error.localizedDescription)
            }
        }

Note: Don't forget to call stopAccessingSecurityScopedResource() after you're done!

You can find more Infomation in the Apple Documentation.

5      

Perfect, cameronshemilt! This does it for me -- thanks so much! (I would not have figured this out on my own...)

3      

@jturo  

Thanks, can confirm it solved my issue!

3      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.