2

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?

MongoTheGeek
  • 294
  • 1
  • 10
  • I've worked with code like that and I consider it a symptom of a bigger problem. I suggest it's better for the caller to know which thread it's on and do the right thing. – Phillip Mills Sep 03 '20 at 20:50

1 Answers1

1

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)
}
gcharita
  • 7,729
  • 3
  • 20
  • 37