7

Using swift 3 in Xcode 8.2.1 for an iOS App.

I understand that I need an autoreleasepool block when dispatching some processing on a new thread. But is it needed when dispatching back on main thread ?

Suppose we are on the main thread and do the following:

    DispatchQueue.global(qos: .background).async {
        autoreleasepool {
            //***** do something in the background
        } // autoreleasepool

        DispatchQueue.main.async {
            //***** do something on the main thread when background job is done
            //***** does this something need to be enclosed in an autoreleasepool block ?
        } // DispatchQueue.main.async

    } // DispatchQueue.global
KerCodex
  • 305
  • 5
  • 9

2 Answers2

14

DispatchQueue has an "autorelease frequency" attribute, which decides if every workitem is automatically surrounded by autorelease{} or not. It's documented in dispatch/queue.h and not in Apple's documentation, so I can't link to it; attaching screenshots from the headers.

  • DispatchQueue.main has autorelease frequency .workitem (which means autorelease each dispatch_async)
  • DispatchQueue.global has it set to .never (never autorelease automatically; it's up to you)
  • DispatchQueue.init creates one set to .inherit. By default, a new queue targets the global queue, which means it's implicitly .never.

documentation screenshot of .never

Note that this attribute only applies to .async(). If you do .sync(), you must always manually manage the autorelease situation.

docu screenshot of dispatch_sync

To answer your question: No. On main thread, you don't have to wrap your async block with autorelease{}. For any other queue, you either need to set the attribute or manually wrap in autorelease{}.

I recommend never dispatching directly to DispatchQueue.global if there's a risk something would be autoreleased, as that would either leak or end up in a never-emptied pool. Instead, create your own queues with explicit autorelease pool policy.

nevyn
  • 7,052
  • 3
  • 32
  • 43
  • Could you link to the docs where these screenshots are from? – tmm1 Dec 08 '20 at 01:25
  • @tmm1 `DISPATCH_AUTORELEASE_FREQUENCY_NEVER` is at https://github.com/apple/swift-corelibs-libdispatch/blob/f13ea5dcc055e5d2d7c02e90d8c9907ca9dc72e1/dispatch/queue.h#L745-L748 – nolanw Dec 09 '20 at 17:58
  • 1
    @tmm1 and the blurb about autorelease frequency is at https://github.com/apple/swift-corelibs-libdispatch/blob/f13ea5dcc055e5d2d7c02e90d8c9907ca9dc72e1/dispatch/queue.h#L770-L771 – nolanw Dec 09 '20 at 17:59
1

You don't create new threads using GCD (dispatch family of functions). Those are system queues that already exist and you don't need additional autorelease pools for them.

If you were to manually use NSThread or Thread in Swift, then you would have to worry about that, but generally you don't need this for even relatively advanced background processing.

jlehr
  • 15,557
  • 5
  • 43
  • 45
Alistra
  • 5,177
  • 2
  • 30
  • 42
  • that sounds sensible to me, but there were so many examples around the net that included autoreleasepool blocks... So, if I understand well, the first autoreleasepool in my example is also unnecessary. Is that correct ? – KerCodex Jan 22 '17 at 17:08
  • 1
    This isn't even required for `NSThread` anymore, or even pthreads. http://stackoverflow.com/a/30519746/97337 And of course it also isn't needed for queues you create (so not just system-created queues). You only need to create autoreleasepools now when you're going to create a lot of temporary objects that you want to control the lifetime of (usually to prevent a spike in memory due to loops). – Rob Napier Jan 22 '17 at 17:45
  • Incorrect on both points: 1) GCD do not create autorelease pools for all their queues; only queues where you ask for automatic pools. 2) the automatic autoreleasepool for NSThread/Thread/pthread is an emergency fallback that won't be emptied until thread dies, so depending on that behavior will lead to memory bloat in your app. – nevyn Jun 15 '19 at 12:10