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.) (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. Thank you very much, Nate Chandler
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users