Matthew Seaman Matthew Seaman - 1 month ago 29
Swift Question

AutoreleaseFrequency on DispatchQueue in Swift 3 beta 5

In Xcode 8 beta 5, the initializer for

DispatchQueue
has changed to accept separate arguments for qos (quality of service), attributes, and autorelease frequency. While I did not have any problems converting my code to work with the new initializer, I am uncertain on the meaning of some of the attributes, particularly autorelease frequency.

For example, in Xcode 8 beta 3 and Swift 3, I was able to create a serial
DispatchQueue
as such:

let serialQueue = DispatchQueue(label: "Concurrent Map", attributes: [.serial, .qosBackground], target: nil)


In Xcode 8 beta 5 and Swift 3:

let serialQueue = DispatchQueue(label: "Concurrent Map", qos: .background, attributes: [], autoreleaseFrequency: .inherit, target: nil)


My questions are:


  • In the new DispatchQueue.Attributes, .serial is no longer a member. Does this mean that the absence of .concurrent creates a serial queue. An initial test I did in Swift Playgrounds seems to confirm this. Can anyone else confirm?

  • I see that DispatchQueue.AutoreleaseFrequency is a new type with .inherit, .never, and .workItem. What do these mean? I did some research on GCD and autoreleasing but I'm not very familiar with the concept of autorelease pools.


Answer

I couldn't find any official documentation of those new attributes (it's probably being worked on), but given the existing GCD documentation, and reading between the lines, it's pretty easy to intuit what's intended here.

In the new DispatchQueue.Attributes, .serial is no longer a member. Does this mean that the absence of .concurrent creates a serial queue. An initial test I did in Swift Playgrounds seems to confirm this. Can anyone else confirm?

Yes. A queue is either serial or concurrent. Most queues you create will be serial, so you only need to set them to be concurrent if you don't want the default behavior.

I see that DispatchQueue.AutoreleaseFrequency is a new type with .inherit, .never, and .workItem. What do these mean? I did some research on GCD and autoreleasing but I'm not very familiar with the concept of autorelease pools.

Previously, DispatchQueues would pop their autorelease pools at unspecified times (when the thread became inactive). In practice, this meant that you either created an autorelease pool for each dispatch item you submitted, or your autoreleased objects would hang around for an unpredictable amount of time.

Non-determinism is not a great thing to have (particularly in a concurrency library!), so they now allow you to specify one of three behaviors:

.inherit: Not sure, probably the previously-default behavior

.workItem: Create and drain an autorelease pool for each item that gets executed

.never: GCD doesn't manage autorelease pools for you

Out of all of these, you're likely only going to want to use .workItem, because it'll clean up your temporary objects when the item completes. The other options are presumably for either buggy code that depends on the old behavior, or for that rare user that actually wants to manage this stuff themselves.


Actually, thinking about it a bit more, if you're submitting work items that are Swift-only (they don't call into any Objective-C code), then .never is probably safe & correct. Given that any/all Swift standard library classes might call some Objective-C code, you'd probably want to limit this to computations which reside entirely within your own Swift code.