<div>Hi Ole,</div><div><br></div><div>Thank you very much for your response. </div><div><br></div><div>I don't believe withExtendedLifetime can help out here. The trouble is that withExtendedLifetime only extends a lifetime until the end of a scope, synchronously. </div><div><br></div><div>In my case, I want to extend the lifetime of Handle from AsyncHandle's deinit until a closure enqueued asynchronously (from AsyncHandle's deinit) is invoked. Using withExtendedLifetime, I could only extend the lifetime of Handle until the end of AsyncHandle's deinit method.</div><div><br></div><div>I want to write</div><div><br></div><div>class AsyncHandle {</div><div><br></div><div> let handle: Handle</div><div><br></div><div> deinit {</div><div> let handle: Handle = self.handle</div><div> q.async {</div><div> letHandleDieNow(handle)</div><div> }</div><div> }</div><div><br></div><div>}</div><div><br></div><div>If I tried to use withExtendedLifetime, I could only write</div><div><br></div><div><div>class AsyncHandle {</div><div><br></div><div> let handle: Handle</div><div><br></div><div> deinit {</div><div> let handle: Handle = self.handle</div><div> withExtendedLifetime(handle) { handle in</div><div> q.async {</div><div> // This is where I want handle to finally be deinitialized</div><div> }</div><div> }</div><div> // This is where handle is actually deinitialized, prior (probably) to the invocation of the closure passed to async</div><div> }</div><div><br></div><div>}</div></div><div><br></div><div>Please let me know if I am misunderstanding your suggestion or the withExtendedLifetime API.</div><div><br></div><div>Thank you very much,</div><div>Nate Chandler</div><div><br></div><div><br><div class="gmail_quote"><div>On Mon, Feb 27, 2017 at 12:31 PM Ole Begemann <<a href="mailto:ole@oleb.net">ole@oleb.net</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 27/02/2017 15:17, Nate Chandler via swift-users wrote:<br class="gmail_msg">
> Hello all,<br class="gmail_msg">
><br class="gmail_msg">
> I'm encountering a behavior around object lifetime and deinitialization<br class="gmail_msg">
> that is surprising to me. Here's an approximation of what I'm encountering:<br class="gmail_msg">
><br class="gmail_msg">
> I have a class Handle whose deinit must execute on a certain queue<br class="gmail_msg">
> (let's call it q--in my case it is a global queue). I have a second<br class="gmail_msg">
> class AsyncHandle which owns a Handle and needs to be able to deinit on<br class="gmail_msg">
> any queue. There's a tension to resolve between the deinitialization<br class="gmail_msg">
> contracts of Handle and AsyncHandle. To resolve it, in AsyncHandle's<br class="gmail_msg">
> deinit, I am binding the owned instance of Handle to a local variable,<br class="gmail_msg">
> dispatching async onto the q, and from the async closure, calling<br class="gmail_msg">
> extendLifetime with the Handle, where extendLifetime is the following:<br class="gmail_msg">
><br class="gmail_msg">
> @inline(never) func extendLifetime<T : AnyObject>() {}<br class="gmail_msg">
><br class="gmail_msg">
> AsyncHandle's deinit looks like<br class="gmail_msg">
><br class="gmail_msg">
> deinit {<br class="gmail_msg">
> let handle = self.handle<br class="gmail_msg">
> q.async {<br class="gmail_msg">
> extendLifetime(handle)<br class="gmail_msg">
> }<br class="gmail_msg">
> }<br class="gmail_msg">
><br class="gmail_msg">
> This approach seems to work--the Handle gets deinit on q, the<br class="gmail_msg">
> appropriate queue. Most of the time. In the debugger, there is never a<br class="gmail_msg">
> problem. Occasionally and inconsistently, on some devices, I am,<br class="gmail_msg">
> however, seeing a behavior that _seems_ to be the synchronous<br class="gmail_msg">
> deallocation of Handle from AsyncHandle's deinit on the queue that<br class="gmail_msg">
> AsyncHandle happens to be deinitializing on (not q). If that is indeed,<br class="gmail_msg">
> the behavior I'm seeing, I do not understand why it is happening.<br class="gmail_msg">
><br class="gmail_msg">
> A few questions:<br class="gmail_msg">
> (1) Given an object B owned (exclusively--no other objects have<br class="gmail_msg">
> references to A) by an object A, is it legal to extend the lifetime of B<br class="gmail_msg">
> in the deinit of A? (It might conceivably not be legal if there is a<br class="gmail_msg">
> rule such as the following: when the runtime observes that an object R<br class="gmail_msg">
> referenced by a field of a deinitializing object O has a reference count<br class="gmail_msg">
> of one, it assumes that R must die when O dies and consequently puts R<br class="gmail_msg">
> into some moribund state from which there is no revivification.)<br class="gmail_msg">
> (2) If it is legal, is calling extendLifetime from a dispatch async the<br class="gmail_msg">
> appropriate way to do it?<br class="gmail_msg">
> (3) Is my "implementation" (such as it is) of extendLifetime correct?<br class="gmail_msg">
> (I can't use the stdlib's _fixLifetime, unfortunately, or even<br class="gmail_msg">
> implement extendLifetime in the same way.)<br class="gmail_msg">
<br class="gmail_msg">
Have you tried using the standard library's withExtendedLifetime(_:_:)<br class="gmail_msg">
function?<br class="gmail_msg">
<br class="gmail_msg">
> (4) Does optimization based on visibility enter into this? In my case<br class="gmail_msg">
> the AsyncHandle is fileprivate.<br class="gmail_msg">
> (5) Is there any entirely different approach to satisfy the following<br class="gmail_msg">
> requirements? (a) AsyncHandle be releasable/deinitializable on any<br class="gmail_msg">
> thread. (b) Handle be deinitialized only on some dispatch queue q. (c)<br class="gmail_msg">
> AsyncHandle has the only reference to Handle.<br class="gmail_msg">
<br class="gmail_msg">
</blockquote></div></div>