-
Notifications
You must be signed in to change notification settings - Fork 6
Closed
Labels
enhancementNew feature or requestNew feature or request
Milestone
Description
We should at least do this for .main
, if not other contexts.
PMHTTP does something similar for its completion blocks. It uses code like
extension HTTPManagerRequestPerformable {
/// A workaround to ensure the completion block deinits on the queue where it's fired from.
///
/// Ownership of blocks is not passed directly into the queue that runs them, which means they could get
/// deallocated from the calling thread if the queue runs the block before control returns back to that
/// calling thread. We guard against that here by forcing the completion block to be released immediately
/// after it's fired. This ensures that it can only be deallocated on the completion queue or the thread that
/// creates the task in the first place.
fileprivate func completionThunk(for block: @escaping (_ task: HTTPManagerTask, _ result: HTTPManagerTaskResult<ResultValue>) -> Void) -> (HTTPManagerTask, HTTPManagerTaskResult<ResultValue>) -> Void {
var unmanagedThunk: Unmanaged<Thunk<(HTTPManagerTask, HTTPManagerTaskResult<ResultValue>), Void>>? = Unmanaged.passRetained(Thunk(block))
return { (task, result) in
let thunk = unmanagedThunk.unsafelyUnwrapped.takeRetainedValue()
unmanagedThunk = nil // effectively a debug assertion that ensures we don't call the completion block twice
thunk.block((task, result))
}
}
}
/// A wrapper class that allows us to stuff the block into an `Unmanaged`.
private class Thunk<Args,ReturnValue> {
let block: (Args) -> ReturnValue
init(_ block: @escaping (Args) -> ReturnValue) {
self.block = block
}
}
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request