Basic expressive Swift background thread execution I created a basic background thread class in swift to replace the ugliness of:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { () -&gt; Void in
  // background thread code
  dispatch_async(dispatch_get_main_queue()) { () -&gt; Void in
      // done, back to main thread
  }
}


with the expressiveness of:

Background { () -&gt; () in
    // background code
  }.afterInterval(3) { () -&gt; () in
    // main thread, run after interval IF not done
  }.completion { () -&gt; () in
    // done, main thread
  }


afterInterval and completion are optional and interchangeable.

How reliable is this approach? Can we ever return from init(task) before completion is added, using the dot syntax? I have tested to my abilities and it seems rather bulletproof, but am wondering about the thoughts here.

class Background {

  private var done = false {
    didSet {
      if done {
        taskInterval = nil
        dispatch_async(dispatch_get_main_queue()) { () -&gt; Void in
          completion?()
        }
      }
    }
  }

  private var taskInterval: (() -&gt; ())?
  private var completion: (() -&gt; ())?

  init(task: () -&gt; ()) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { () -&gt; Void in
      task()
      self.done = true
    }
  }

  func afterInterval(interval: NSTimeInterval, closure: () -&gt; ()) -&gt; Background {
    taskInterval = closure
    let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(interval * Double(NSEC_PER_SEC)))
    dispatch_after(delayTime, dispatch_get_main_queue()) { [weak self] in
      self?.taskInterval?()
    }
    return self
  }

  func completion(closure: () -&gt; ()) -&gt; Background {
    completion = closure
    return self
  }

}


"SwiftyThreads" on Github
Yes, I see what you mean: there do appear to be dodgy race conditions. I do like where you are going with this, though – dot syntax and all. Still I found at least one failing test. If you paste your code in a playground and then add the following:

/* your code here */

import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true

var i = 0

Background {
    i += 1 // don't call `print` here!
}.afterInterval(0) {
    i += 10
}.completion {
    i += 100
}

let t = dispatch_time(DISPATCH_TIME_NOW, Int64(NSEC_PER_SEC))
dispatch_after(t, dispatch_get_main_queue()) {
    print(i)
}

// prints: 101 (instead of 111)


True, delay of 0 seems a little contrived, but it does prove that your worries are founded. One way around this is to trigger a dispatch of those closures on demand (and repeatedly):

import Foundation
class Background {
    let qos: qos_class_t
    let task: (() -&gt; ())?
    private(set) var delay: NSTimeInterval? = nil
    private(set) var delayedTask: (() -&gt; ())? = nil
    private(set) var completionHandler: (() -&gt; ())? = nil

    init(_ qos: qos_class_t = QOS_CLASS_BACKGROUND, task: (() -&gt; ())? = nil) {
        self.qos = qos
        self.task = task
    }

    func delay(interval: NSTimeInterval, task: () -&gt; ()) -&gt; Background {
        self.delay = interval
        self.delayedTask = task
        return self
    }

    func completion(task: () -&gt; ()) -&gt; Background {
        self.completionHandler = task
        return self
    }

    func async() {
        dispatch_async(dispatch_get_global_queue(qos, 0)) { // TODO: unnecessary if `task == nil` 
            self.task?()
            if let delayedTask = self.delayedTask, let delay = self.delay {
                let t = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * NSTimeInterval(NSEC_PER_SEC)))
                dispatch_after(t, dispatch_get_main_queue(), delayedTask)
            }
            if let completionHandler = self.completionHandler {
                dispatch_async(dispatch_get_main_queue(), completionHandler)
            }
        }
    }
}


Which can be used like so:

import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true

var i = 0

let bg = Background {
    i += 1
}.delay(0) {
    i += 10
}.completion {
    i += 100
}

// nothing dispatched yet!

bg.async() // repeated invocations possible
bg.async()

Background().delay(1) {
    print(i)
}.async()

// prints: 222 (as it should)


In addition, I would probably rename Background...