18

Asynchronous programming is a must for responsive user interfaces when application have to communicate over unpredictable networks (e.g. smart phone applications). The user interface must remain responsive while waiting for results to come back from servers somewhere over the internet.

In most languages, the application programmer has to implement their own state machines (maybe using closures) to respond to asynchronous callbacks and/or coordinate multiply threads using locks.

Both of these are very error prone and not for the fait hearted!

(c# introduced the async keyword to help with this, only time (at least 5 years) will tell if it is a good solution.)

Does Swift have any built in support to assist the writing of asynchronous code?

Ian Ringrose
  • 51,220
  • 55
  • 213
  • 317
  • 2
    possible duplicate of [How does Apple's new programming language Swift handle blocks and asynchronous requests?](http://stackoverflow.com/questions/24006398/how-does-apples-new-programming-language-swift-handle-blocks-and-asynchronous-r) – weston Jun 03 '14 at 09:04

2 Answers2

13

While it isn't a built-in language feature, it may be interesting to note that it's possible to implement C# style async/await for Swift, and that because of the special syntax afforded to the last closure argument of a function call, it even looks like it might be part of the language.

If anyone is interested, you can get code for this on Bitbucket. Here's a quick taster of what's possible:

let task = async { () -> () in
  let fetch = async { (t: Task<NSData>) -> NSData in
    let req = NSURLRequest(URL: NSURL.URLWithString("http://www.google.com"))
    let queue = NSOperationQueue.mainQueue()
    var data = NSData!
    NSURLConnection.sendAsynchronousRequest(req,
                                            queue:queue,
      completionHandler:{ (r: NSURLResponse!, d: NSData!, error: NSError!) -> Void in
        data = d
        Async.wake(t)
      })
    Async.suspend()
    return data!
  }

  let data = await(fetch)
  let str = NSString(bytes: data.bytes, length: data.length,
                     encoding: NSUTF8StringEncoding)

  println(str)
}

Also, if you want something like @synchronized, try this:

func synchronized(obj: AnyObject, blk:() -> ()) {
  objc_sync_enter(obj)
  blk()
  objc_sync_exit(obj)
}

var str = "A string we can synchronise on"

synchronized(str) {
  println("The string is locked here")
}
al45tair
  • 4,405
  • 23
  • 30
  • 1
    This is nice, though frankly should be standard to make code more readable. – Blaze Jun 14 '14 at 01:28
  • Is this safe? Using setjmp/longjmp in Objective-C conflicts with autorelease pools (which are implemented as a shadow stack in the runtime, but are not a public ABI) - as far as I'm aware, Swift also uses autorelease. – pmdj Aug 09 '15 at 11:51
  • 1
    in 2nd example what if blk throws an exception? – gregswiss Sep 25 '15 at 01:36
  • @gregswiss When I originally wrote this, Swift didn't have exceptions. It still doesn't have the kind of exceptions you’re thinking of. If, on the other hand, the block in question throws Objective-C exceptions, you’re in trouble; but that’s true generally for Swift code. – al45tair Mar 17 '16 at 11:03
  • @pmdj That’s a good point; it probably isn’t autorelease-safe, as it stands. It should be possible to fix it by tinkering with the pthread key that the autorelease system uses, though this is of course a massive hack. I'm not sure Swift does use autorelease, FWIW. – al45tair Mar 17 '16 at 11:08
11

Swift's approach to asynchronous programming is the same as Objective C's: use Grand Central Dispatch. You can pass closures to gcd dispatch_ functions, just as in ObjC. However, for aesthetic reasons, you can also pass your closure (block) after the close parentheses:

dispatch_async(dispatch_get_main_queue()) {
    println("async hello world")
}
Ben Gottlieb
  • 85,404
  • 22
  • 176
  • 172
  • Objective C has the @synchronization keyword, so this doesn't appear to be true. – Blaze Jun 03 '14 at 10:27
  • @Blaze You mean @synchronized? That's really syntactic sugar for calling `objc_sync_enter()`/`objc_sync_exit()`. You can do that in Swift if you like, and you can even add similar syntax if you like. – al45tair Jun 13 '14 at 09:24
  • `@synchronized` is a mechanism that predates GCD and is generally consider to be not as good as using GCD. Notably, it uses a recursive lock, which is a much more expensive synchronization operation than using a dispatch queue – Lily Ballard Jun 21 '14 at 20:26