0

I've read just about every question and answer about closing a View that's loaded in a UIHostingController. They all seem to use some variation on using a button to dismiss the view. In my view the user is uploading an object and on completion I'd like to close the current view and go back to the previous one. The simplest application of this that I could find is here:

https://stackoverflow.com/a/57728357/1321751

..and I've implemented it as follows:

UploadViewController

 required init?(coder: NSCoder) {
        super.init(coder: coder, rootView: UploadView())
        rootView.dismissAction = dismiss
    }
    func dismiss() {
            dismiss(animated: true, completion: nil)
        }

HostingController

struct UploadView: View {
    @State var dismissAction: (() -> Void)?

var body: some View {
        
        VStack {
Button(action: {
                let uiImage: UIImage = self.selectedImage.asUIImage()
                let imageData: Data = uiImage.jpegData(compressionQuality: 0.1) ?? Data()
                 let imageStr: String = imageData.base64EncodedString()
                // let imageStr = String(decoding: imageData, as: UTF8.self)
                
                if let data9 = UserDefaults.standard.data(forKey: "current") {
                    do {
                        // Create JSON Decoder
                        let decoder = JSONDecoder()

                        // Decode Note
                        let current = try decoder.decode(Current.self, from: data9)
                        self.uid = current.id
                        self.uname = current.uname
                        print(current.fid as Any)

                    } catch {
                        print("Unable to Decode User (\(error))")
                    }
                    }
    var urlRequest = URLRequest(url: url)
urlRequest.addDataField(named: remoteName, data: imageData, mimeType: "img/jpeg")
     URLSession.shared.dataTask(with: urlRequest, completionHandler: {
                        (data, response, error) in
                        guard let data = data else {
                            print("Error in Data")
                            return
                        }
    let responseStr: String = String(data: data, encoding: .utf8) ?? ""
    Button("Dimiss", action: dismissAction!)
     }).resume()
                    
                    
                }, label: {
            Text("Upload Image").font(.callout).padding(8).foregroundColor(Color.white).background(Color.black).overlay(
                RoundedRectangle(cornerRadius: 6)
                    .stroke(Color.white, lineWidth: 3)
        )
                
        })
       
    }
    .sheet(isPresented: $showImagePicker, content: {
        ImagePicker(image: self.$selectedImage)
    })
}

This follows the example code pretty much perfectly... but nothing happens. The view doesn't dismiss at all. The operation does complete. The file gets uploaded... Then nothing.

Every other example that I've found of dismissing a view from a UIHostingController has been some variation of this. And I haven't been able to get a single one of them to work.

Any help would be appreciated. OH! And could somebody tell me WHY it's a "button"... instead of just calling upon the "dismiss" action? Why does it HAVE to be a button?

mystic cola
  • 1,465
  • 1
  • 21
  • 39
  • 1
    This code doesn't make sense -- you shouldn't have `URLSession.shared.dataTask` in the middle of your view hierarchy in SwiftUI. The view hierarchy is for views. Imperative/procedural code should be in something like `onAppear` or `task`. Conversely, your `Button` shouldn't be within the procedural code. – jnpdx Nov 05 '22 at 16:19
  • The "URLSession" bit is in the middle of a Button action. This is just the tail end of some extremely long , complex code. A summary if you will. Person selects a file, uploads that file, and, on response... it should close the view. I don't want the Dismiss button at all. The problem is that I've found no other way to dismiss a UIHostingView. It always comes down to "Button". All I want to do is dismiss the view after the response string. – mystic cola Nov 05 '22 at 16:28
  • 1
    You should include a [mre] -- including code that doesn't represent the issue just confuses things, as it's not clear what is going wrong in the real situation. In terms of needing a `Button`, you can call `dismissAction` from anywhere. – jnpdx Nov 05 '22 at 16:35
  • Updated for clarity. So how would I call dismissAction there without the whole button nonsense? – mystic cola Nov 05 '22 at 20:54
  • Call dismissAction() when you want to dismiss. By the way, there’s no reason for it to be `@State` – jnpdx Nov 05 '22 at 21:03
  • You can format your code by using ctrl-i in Xcode. – jnpdx Nov 05 '22 at 21:04
  • Thanks. This is what I get: Main Thread Checker: UI API called on a background thread: -[UIViewController dismissViewControllerAnimated:completion:] – mystic cola Nov 05 '22 at 21:46
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/249358/discussion-between-mystic-cola-and-jnpdx). – mystic cola Nov 05 '22 at 21:59

1 Answers1

0

Ok. So a few things in my code needed to be rewritten. First off... the whole "Button" thing was unnecessary:

HostingController

//Change:
 let responseStr: String = String(data: data, encoding: .utf8) ?? ""
    Button("Dimiss", action: dismissAction!)
     }).resume()

//To:
 let responseStr: String = String(data: data, encoding: .utf8) ?? ""
    dismissAction!()
     }).resume()

You'll get a purple warning that "dismissAction" needs to be called on the main thread. So back in...

UploadViewController

DispatchQueue.main.async {
        
            self.dismiss(animated: true, completion: nil)
            
        }

The part I forgot about was that I was also running a navigation controller. So nothing happened when trying to dismiss the view. I had to thus modify the code:

DispatchQueue.main.async {
        
           // self.dismiss(animated: true, completion: nil)
            self.navigationController?.popViewController(animated: true)
        }

And that's it. Now it works. (Special thanks to @jnpdx for some helpful advice.

Hopefully this helps someone who happens to run into this... admittedly unusual circumstance.

mystic cola
  • 1,465
  • 1
  • 21
  • 39