Temporarily switch from background thread to main thread (and back?)

I've got a function that runs on a background thread and downloads files:

func downloadFiles(remoteFolder rf:String, localFolder lf:String, completion: @escaping (_ success:Bool, _ err: String) -> Void) {
    DispatchQueue.global(qos:.background).async {
        ...
        DispatchQueue.main.async {
            completion(successBool, errorMsg)
        }
    }
}

It's called by my main ViewController:

myDownloadClass.downloadFiles(remoteFolder: rf, localFolder: lf, completion: { (success, error) in
    ... //More stuff here
}

Is there a way to temporarily switch back to the main thread (and with that also to the VC) in downloadFiles, so I can add the name of the file that's next in the download list to an e.g. UIAlertController but without tripping off everything that should be done after downloading everything actually finished ("More stuff here")?

I'm using Xcode 13 with Swift 5 and iOS 13.

Could you explain more what you want ?

You download files. When do you want to switch to the main thread ? Each time a file is downloaded ?

Did you consider dispatch groups ?

Also may have a look here https://stackoverflow.com/questions/24056205/how-to-use-background-thread-in-swift

The first thing that comes to mind would be using a notification.

func downloadFiles(remoteFolder rf:String, localFolder lf:String, completion: @escaping (_ success:Bool, _ err: String) -> Void) {
    DispatchQueue.global(qos:.background).async {
        let fileName:String = (use whatever setter you have from your loop)
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateDownloadFileName", object: nil, userInfo: ["fileName":fileName]))
        ...
        DispatchQueue.main.async {
            completion(successBool, errorMsg)
        }
    }
}

In your ViewController:

let myLabel = NSTextField(labelWithString: "")

override func viewDidLoad() {
    setupNotificationCenter()
}

func updateDownloadFileName(notification: Notification) {
    if let data = notification.userInfo as? [String:String] {
        if let string = data["fileName"] {
            myDownloadLabel.stringValue = string
        }
    }
}

func setupNotificationCenter() {
    NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "updateDownloadFileName"), object: nil, queue: nil, using: updateDownloadFileName)
}

If you don't want to use Notifications then you could pass the Label to the method and update the stringValue through a dispatch to the main thread:

func downloadFiles(remoteFolder rf:String, localFolder lf:String, myLabel:NSTextField, completion: @escaping (_ success:Bool, _ err: String) -> Void) {
    DispatchQueue.global(qos:.background).async {
        let fileName:String = (use whatever setter you have from your loop)
        DispatchQueue.main.async {
            myLabel.stringValue = fileName
        }
        ...
        DispatchQueue.main.async {
            completion(successBool, errorMsg)
        }
    }
}
Temporarily switch from background thread to main thread (and back?)
 
 
Q