Search code examples
swiftprogram-entry-pointdispatch

Swift Dispatch Main


I have code that I am repeating a bunch. I want to update things on the main thread, UI stuff.

public func closeGraph() {
   DispatchQueue.main.sync{_closeGraph()}
}

That's easy enough, but what if user interaction triggers it and I am already on the main thread. ++ungood.

public func closeGraph() {
    if Thread.isMainThread {
        _closeGraph()
    } else {
        DispatchQueue.main.sync{_closeGraph()}
    }
}

Oops openGraph() throws...

public func openGraph() throws  {
    do {
        if Thread.isMainThread {
            try _openGraph()
        } else {
            try DispatchQueue.main.sync{try _openGraph()}
        }
    } catch {
        throw error
    }
}

Is there a better way to this so i don't have to copy paste it everywhere?


Solution

  • You can extract your check to a generic function like this:

    public func mainQueue(execute block: () throws -> Void) rethrows {
        if Thread.isMainThread {
            try block()
        } else {
            try DispatchQueue.main.sync{ try block() }
        }
    }
    

    then if your _closeGraph() function doesn't throw any error, your code will be like this:

    public func closeGraph() {
        mainQueue(execute: _closeGraph)
    }
    

    and if your _closeGraph() function throws, your code will be like this:

    public func closeGraph() {
        do {
            try mainQueue(execute: _closeGraph)
        } catch {
            print(error)
        }
    }
    

    As you can see you will need to write the handling of the throwing function every time.

    Update: If you have a generic error handling in mind, you can hide the do-catch statement in mainQueue(execute:) function like this:

    public func mainQueue(execute block: () throws -> Void) {
        do {
            if Thread.isMainThread {
                try block()
            } else {
                try DispatchQueue.main.sync{ try block() }
            }
        } catch {
            print(error)
        }
    }
    

    then calling this function will be the same whether the _closeGraph() function is throwing or not:

    public func closeGraph() {
        mainQueue(execute: _closeGraph)
    }