skip to Main Content

From background thread, when UI needs to be updated, it needs to post to DispatchQueue.main using the async(execute:) function, as shown below:

static func executeInUIThread(_ uiThreadFunc: @escaping (Any?) -> Void, _ parms: Any?) {
  DispatchQueue.main.async {
    // Update UI 
    uiThreadFunc(parms)
  }
}

It is possible to access uiThreadFunc and parms inside the closure because closures capture variables from their ‘surrounding context’.

But let’s say, I don’t like the lambda-style (called closures in swift) of programming. How can I do this without closures?

I attempted the following:

static func executeInUIThread(_ uiThreadFunc: @escaping (Any?) -> Void, _ parms: Any?) {
  let workItem = DispatchWorkItem(block: EventLoopMgr.InternalExecuteInUIThread)

  DispatchQueue.main.async(execute: workItem)
}

private static func InternalExecuteInUIThread() {
  // How to execute the uiThreadfunc? This block doesn't take any parameters.
}

It doesn’t work because, the block when initialising the DispatchWorkItem takes no parameters. Therefore, I can’t pass uiThreadFunc and parms to this block.

I can store the uiThreadFunc and parms as static variables, but then it needs to be made multi-thread friendly.

Any easier way to execute in UIThread using DispatchQueue.main but without using closures?

2

Answers


  1. Will this be helpful for you?

    test to trigger it and updateView is one example of your uiThreadFunc

    func test() {
        let aFunc = #selector(updateView)
        let success = executeInUIThread(caller: self, uiThreadFunc: aFunc, "xxx")
    }
    
    func executeInUIThread(caller: NSObject, uiThreadFunc: Selector, _ parms: Any?) -> Bool {
        if caller.responds(to: uiThreadFunc) {
            caller.performSelector(onMainThread: uiThreadFunc, with: parms, waitUntilDone: false)
            return true
        } else {
            return false
        }
    }
    
    @objc func updateView(param: String) { }
    

    For more Info, please
    have a check GCD vs performSelector

    Login or Signup to reply.
  2. In the project I’m working on, it’s a convention not to have anonymous blocks of code in the middle of the function. It doesn’t depict the natural flow of execution

    Okay, so you can make this not anonymous:

    // I made this generic for you :)
    func executeInUIThread<T>(_ uiThreadFunc: @escaping (T) -> Void, _ parms: T) {
        func helper() {
            uiThreadFunc(parms)
        }
        DispatchQueue.main.async(execute: helper)
    }
    

    Here I gave the name helper to the block of code that will be run on the main queue.

    Technically, a local function still counts as a closure according to the Swift Guide, but if all you want to avoid is an "anonymous" block of code, using a local function definitely achieves that.

    If the local function is too much noise, you can move it out of executeInUIThread like this:

    func partiallyApply<T>(_ arg: T, to function: (T) -> Void) -> () -> Void {
        func helper() { function(arg) }
        return helper
    }
    

    Then you can just do:

    DispatchQueue.main.async(execute: partiallyApply(parms, to: uiThreadFunc))
    

    which arguably is more readable. You

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search