[swift-users] Postponing owned object deinitialization

Ole Begemann ole at oleb.net
Mon Feb 27 11:31:50 CST 2017

On 27/02/2017 15:17, Nate Chandler via swift-users wrote:
> Hello all,
> I'm encountering a behavior around object lifetime and deinitialization
> that is surprising to me.  Here's an approximation of what I'm encountering:
> I have a class Handle whose deinit must execute on a certain queue
> (let's call it q--in my case it is a global queue).  I have a second
> class AsyncHandle which owns a Handle and needs to be able to deinit on
> any queue.  There's a tension to resolve between the deinitialization
> contracts of Handle and AsyncHandle.  To resolve it, in AsyncHandle's
> deinit, I am binding the owned instance of Handle to a local variable,
> dispatching async onto the q, and from the async closure, calling
> extendLifetime with the Handle, where extendLifetime is the following:
> @inline(never) func extendLifetime<T : AnyObject>() {}
> AsyncHandle's deinit looks like
> deinit {
>     let handle = self.handle
>     q.async {
>         extendLifetime(handle)
>     }
> }
> This approach seems to work--the Handle gets deinit on q, the
> appropriate queue.  Most of the time.  In the debugger, there is never a
> problem.  Occasionally and inconsistently, on some devices, I am,
> however, seeing a behavior that _seems_ to be the synchronous
> deallocation of Handle from AsyncHandle's deinit on the queue that
> AsyncHandle happens to be deinitializing on (not q).  If that is indeed,
> the behavior I'm seeing, I do not understand why it is happening.
> A few questions:
> (1) Given an object B owned (exclusively--no other objects have
> references to A) by an object A, is it legal to extend the lifetime of B
> in the deinit of A?  (It might conceivably not be legal if there is a
> rule such as the following: when the runtime observes that an object R
> referenced by a field of a deinitializing object O has a reference count
> of one, it assumes that R must die when O dies and consequently puts R
> into some moribund state from which there is no revivification.)
> (2) If it is legal, is calling extendLifetime from a dispatch async the
> appropriate way to do it?
> (3) Is my "implementation" (such as it is) of extendLifetime correct?
>  (I can't use the stdlib's _fixLifetime, unfortunately, or even
> implement extendLifetime in the same way.)

Have you tried using the standard library's withExtendedLifetime(_:_:) 

> (4) Does optimization based on visibility enter into this?  In my case
> the AsyncHandle is fileprivate.
> (5) Is there any entirely different approach to satisfy the following
> requirements?  (a) AsyncHandle be releasable/deinitializable on any
> thread.  (b) Handle be deinitialized only on some dispatch queue q.  (c)
> AsyncHandle has the only reference to Handle.

More information about the swift-users mailing list