change UIVIew visibility during a long func call

Viewed 32

I have a search page with uses OAuth to make an external call to a website for data. Sometimes the data is very quick and others quite long. So I have created a custom object (Searching) to display on screen to indicate that a search is happening (the custom object is just 2 UIImageViews in a UIView)

The problem is that the searching.isHidden = false doesn't actually happen until the end of the func which happens after it gets all the data, even though it is called first. Which is obviously too late.

I tried moving the isHidden to a background thread but get an error saying UIView calls must be on the main thread

I tried moving the display call to its own func with an @escaping callback and then run the search after it returns but it still does not update.

If I remove the search() line it displays properly.

I've also tried forcing a refresh on the object using

self.view.setNeedsLayout()
self.view.setNeedsDisplay()

and it didn't work

class Search {

override func viewDidLoad() {
    
    super.viewDidLoad()

    searching.isHidden = true
}

@IBAction func search(_ sender: Any) {

  
    if self.searching.isHidden == false {
        self.searching.isHidden = true
    }
    else {
        self.searching.isHidden = false
    }

    self.view.setNeedsLayout()
    self.view.setNeedsDisplay()

    //I've also tried using an escaping func to call the isHidden and call back when complete
    //self.searching.show() {
        
        //self.view.setNeedsLayout()
        //self.view.setNeedsDisplay()
        
        //self.search()
    //}
    
    //I've tried an async call 
//    DispatchQueue.main.async {
//        self.search()
//    }
}

func search() {

    keywordText.resignFirstResponder()
    
    //perform OAuth external search

    if results.count > 1 {
        
        searching.isHidden = true
        self.performSegue(withIdentifier: "results", sender: nil)
    }
    
    return
}
}
1 Answers

On iOS (and MacOS) UI updates don’t get displayed until your code returns and the event loop gets a chance to run. Code that makes UI changes and then immediately does a long-running task on the main thread will not see those changes on-screen until the long-running task completes.

One way to handle this is to change you UI and then use dispatchAsync to trigger the long-running task:

searching.isHidden = false
DispatchQueue.main.async {
   // Put your long-running code here.)
}
Related