'SwiftUI: Display file url from Array after user Picks file using DocumentPicker

I followed a tutorial on getting Url from a Document a user chooses and be able to display it on the View. My problem now is I want to add those Url's into an array. Then get the items from the array and print them onto the View. The way it works is the User presses a button and a sheet pops up with the files app. There the user is able to choose a document. After the user chooses the document the Url is printed on the View. To print the Url is use this

    //if documentUrl has an Url show it on the view
    If let url= documentUrl{
             Text(url.absoluteString)
   }

Issue with this is that when I do the same thing the

   If let url= documentUrl 

Is ran before the Url is even added to the array and the app crashes

Here is the full code

    //Add the Urls to the array
    class Article: ObservableObject{
        var myArray:[String] = []

    }

    struct ContentView: View {
        @State private var showDocumentPicker = false
        @State private var documentUrl:URL?
        @State var myString:URL?
        @ObservedObject var userData:Article

        // Func for onDismiss from the Sheet
         func upload() {
             // add the Url to the Array
            DispatchQueue.main.async{
                userData.myArray.append(documentUrl!.absoluteString)
            }
        }

var body: some View {
    VStack{
        //If have Url reflect that on the View
        if let url = documentUrl{
            //Works
            Text(url.absoluteString)
            //doesntwork
            Text(userData.myArray[0])
        }
        
        }
        Button(action:{showDocumentPicker.toggle()},
                        label: {
                     Text("Select your file")
                 })
            .sheet(isPresented: $showDocumentPicker, onDismiss: upload )
        {
                DocumentPicker(url: $documentUrl)
                    }
    }
}

The main thing I want to do the just display the ulrs into the view after the user chooses the document or after the sheet disappears. So if the user chooses 1 Url only one is printed. If another one is chosen after then 2 are show etc. This is the documentPicker code used to choose a document

            struct DocumentPicker : UIViewControllerRepresentable{
        @Binding var url : URL?


func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
    
    //initialize a UI Document Picker
    let viewController = UIDocumentPickerViewController(forOpeningContentTypes: [.epub])
    viewController.delegate = context.coordinator
    print("1")
    return viewController
}

func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {
    print("Swift just updated ")
    print("2")
}

    }


    extension DocumentPicker{
        func makeCoordinator() -> Coordinator {
            Coordinator(self)
        }

class Coordinator:NSObject, UIDocumentPickerDelegate{
    let parent: DocumentPicker
    init(_ documentPicker: DocumentPicker){
        self.parent = documentPicker
    }
    func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
        guard let url = urls.first else{return}
        parent.url = url
        print("3")
    }

}
}

Not sure if maybe I'm not approaching this the correct way? I looked at different tutorial but couldn't find anything.



Solution 1:[1]

An observable object doesn't have a change trigger. To inform that the observable object has changed use one of the following examples:

class Article: ObservableObject {
    @Published var myArray:[String] = []
}

or

class Article: ObservableObject {
    private(set) var myArray:[String] = [] {
        willSet {
            objectWillChange.send()
        }
    }

    func addUrl(url: String) {
        myArray.append(url)
    }
}

official documentation: https://developer.apple.com/documentation/combine/observableobject

Solution 2:[2]

Use .fileImporter presentation modifire (above ios 14)

.fileImporter(isPresented: $showDocumentPicker,
                      allowedContentTypes: [.image],
                      allowsMultipleSelection: true)
        { result in
            // processing results Result<[URL], Error>
        }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 SickMan
Solution 2