Search code examples
iosswiftuiviewuiimageactivity-indicator

Show UIView/UIImage/UITextView while function is running


OBJECTIVE

I am trying to display a UIView, UIImage, and UITextView when a function is running in order to let a user know it is processing (similar to an Activity Indicator, but more customized).

PROBLEM

When the code below is processing, the UIView, UIImage, and UITextView don't display until a moment before the function finishes running (instead of showing as soon the function starts running and hiding when the function finishes).

CURRENT APPROACH:

I have created a UIView (loadingView) which contains and image (loadingIcon) and a textView (loadingText) explaining to the user that the app is processing.

I have also created a function called isLoading, which displays or hides all 3, rather than repeating these lines multiple times. I have tested setting isLoading to true and false in the viewDidLoad to make sure that it is working properly.

@IBOutlet weak var loadingView: UIView!
@IBOutlet weak var loadingIcon: UIView!
@IBOutlet weak var loadingText: UIView!

override func viewDidLoad() {
    super.viewDidLoad()
    isLoading(false)
}


func isLoading(_ loadStatus: Bool) {
    if loadStatus == true {
        loadingView.isHidden = false
        loadingIcon.isHidden = false
        loadingText.isHidden = false
    } else {
        loadingView.isHidden = true
        loadingIcon.isHidden = true
        loadingText.isHidden = true
    }
}

@IBAction func sendButtonPressed(_ sender: AnyObject) {
    isLoading(true)

    ... //process information, which takes some time

    isLoading(false)
}

Any help, suggestions, or thoughts are immensely appreciated. Thank you.


Solution

  • You are running the process on the main queue so your UI appears to hang until it is finished. You need to process the information in the background. A common pattern you might use would be:

    @IBAction func sendButtonPressed(_ sender: AnyObject) {
        isLoading(true)
    
        // Do the processing in the background    
        DispatchQueue.global(qos: .userInitiated).async {
            ... //process information, which takes some time
    
            // And update the UI on the main queue
            DispatchQueue.main.async {
                isLoading(false)
            }
        }
    }