iosswiftuser-interfaceurlsessionnetworkonmainthread

UI is not getting update although using main thread


I am using Xcode and Swift. I have a class for the UIViewController I am using. On this UIViewController I want to present some kind of pop over view with my custom class ConnectionLostView. On this UIView there is an UIButton. If you press the button the tryToReconnect() function is called (which works). This function processes the online data (which works too) and should update my UI using DispatchQueue.main.async { //updating UI } but my UI isn't getting updated (or rather I can't i.e. remove my button from its superview but I can remove self (what exactly works and what doesn't you can see as comment in the code below))

That is the class of the UIViewController I am using to present my view.

class vc: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let connectionStatusView = ConnectionLostView()
        connectionStatusView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(connectionStatusView)

        //setting up the constraints for connectionStatusView
    }
}

This is the class of my UIView:

class ConnectionLostView: UIView {
    let tryAgainButton = UIButton(type: .roundedRect)

    func tryToReconnect() {
        let url = URL(string: "http://worldclockapi.com/api/json/est/now")!
        let config = URLSessionConfiguration.default
        let session = URLSession(configuration: config)
        let task = session.dataTask(with: url) { (data, response, error) in
            if error != nil {
                print(error)
            } else {
                do {
                    if let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any] {
                        if let data = json["data"] as? String {
                            // code for processing the data

                            DispatchQueue.main.async {
                                self.removeFromSuperview() //Does work
                                self.tryAgainButton.removeFromSuperview() // does not work
                            }
                        }
                    }
                } catch {
                    print(error)
                }
            }
        }
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)

        //setting up the button
        let buttonAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 18)]
        let attributedButtonString = NSAttributedString(string: "Try To Reconnect", attributes: buttonAttributes)
        let reconnectButton = UIButton(type: .roundedRect)
        reconnectButton.translatesAutoresizingMaskIntoConstraints = false
        reconnectButton.setAttributedTitle(attributedButtonString, for: .normal)
        reconnectButton.addTarget(self, action: #selector(tryToReconnect), for: .touchUpInside)
        addSubview(reconnectButton)

        // setting up constraints for reconnectButton
    }
}

How can I fix my code so the UI is updated when I press the reconnectButton?


Solution

  • Actually, the thread and the dispatch queue are red herrings. The problem is merely that self.tryAgainButton is a reference to a button that is not in the interface to begin with. It is off in thought-space somewhere. It has no superview and is not visible. Therefore you call removeFromSuperview on it and nothing happens.

    You did add a button to the interface (reconnectButton). [You did that in a completely wrong way, but what's wrong with the way you did it would be a subject for a different question!] But you never set self.tryAgainButton to reconnectButton, so they are not the same buttons. You have two buttons, the one in the interface (reconnectButton) and the one off in thought-space (self.tryAgainButton).