Object resurrection when using C callbacks from Swift - swift

I'm trying to access a C API from Swift that requires the use of C callbacks.
typedef struct {
void * info;
CFAllocatorRetainCallBack retain;
CFAllocatorReleaseCallBack release;
} CFuncContext;
typedef void (* CFuncCallback)(void * info);
CFuncRef CFuncCreate(CFuncCallback callback, CFuncContext * context);
void CFuncCall(CFuncRef cfunc);
void CFuncRelease(CFuncRef cfunc);
CFuncCreate stores the callback and context on the heap (using malloc), then calls the retain callback to retain the info pointer. CFuncCall simply invokes the callback for demonstration purposes, and CFuncRelease calls the release callback, then frees the memory.
In the Swift code I want to use a dedicated object for info that keeps a weak reference back to my main object. When the main object is deinited, CFuncRelease is called to also clean up the C API memory.
This way, even if the C API decides to perform some delayed callbacks from different run loops, it always has a valid info pointer until it decides to invoke the release callback when it is finally done. Just some defensive programming :)
The info object has this structure:
final class CInfo<T: AnyObject> {
/// This contains the pointer back to the main object.
weak private(set) var object: T?
init(_ object: T) {
self.object = object
}
/// This variable is used to hold a temporary strong
/// `self` reference while retainCount is not 0.
private var context: CInfo<T>?
/// Number of times that `retain` has been called
/// without a balancing `release`.
private var retainCount = 0 {
didSet {
if oldValue == 0 {
context = self
}
if retainCount == 0 {
context = nil
}
}
}
func retain() {
++retainCount
}
func release() {
--retainCount
}
}
My main object SwiftObj uses the C API.
final class SwiftObj {
typealias InfoType = CInfo<SwiftObj>
private lazy var info: InfoType = { InfoType(self) }()
private lazy var cFunc: CFuncRef = {
var context = CFuncContext(
info: &self.info,
retain: { UnsafePointer<InfoType>($0).memory.retain(); return $0 },
release: { UnsafePointer<InfoType>($0).memory.release() }
)
return CFuncCreate(
/* callback: */ cFuncCallback,
/* context: */ &context
)
}()
func call() {
CFuncCall(cFunc)
}
deinit {
CFuncRelease(cFunc)
}
init() {
call()
}
}
func cFuncCallback(info: UnsafeMutablePointer<Void>) {
print("==> callback from C")
}
In my testing code, I first allocate a SwiftObj via an IBAction. Then, I set the reference back to nil again via a second IBAction.
The automated cleanup code should now properly deinit the SwiftObj, and from there the C API should be notified that it should clean up its memory. Then, the release callback on the info pointer should be invoked, which results in the info pointer's reference count reaching zero, and also deallocating the info pointer.
However, the deinit theory doesn't seem to work out. After SwiftObj's final reference is removed, another reference is added back when the release callback closure is invoked, and another reference is re-added during the CInfo.release method (as observed using Instrument's Allocations tracker). Behaviour also depends on the timings - e.g. the number of log statements.
With a minimal sample like the one below, it crashes immediately in the initial release callback closure with either of these two messages depending on the timings - first one is more common, second one can be achieved by a fast space tab space if you are lucky. Maybe there's even more - as I said, in my full example if you put in enough log statements sometimes it prolongs the final cleanup of the SwiftObj enough so that you can see the actual resurrection happening.
EXC_BAD_ACCESS (code=1, address=0x0)
EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
Minimal example can be downloaded here:
https://scriptreactor.com/Resurrection.zip
Run, then hit the Start button, then hit the Stop button. Welcome to the nightmare.
Instruments' Allocations view can also be quite interesting.

Seems like a compiler bug. Workaround is to remove the lazy attribute of the info instance variable.
https://bugs.swift.org/browse/SR-74

Related

Break Swift closure retain circle with not weak explicit capture

The following Swift by Sundell article points out that in some cases is enough to make a explicit capture of a property inside the class to break the references retain cycle. This is the exact example:
class ImageLoader {
private let cache = Cache<URL, Image>()
func loadImage(
from url: URL,
then handler: #escaping (Result<Image, Error>) -> Void
) {
// Here we capture our image loader's cache without
// capturing 'self', and without having to deal with
// any optionals or weak references:
request(url) { [cache] result in
do {
let image = try result.decodedAsImage()
cache.insert(image, forKey: url)
handler(.success(image))
} catch {
handler(.failure(error))
}
}
}
}
This way you could avoid posterior null checks to improve readability. It would be usefull with combine like it is explained in the following article
I don't understand why this breaks the retain circle as [cache] capture is still a strong reference to the ImageLoader property
The cache property refers to an instance of Cache, which is a separate object from the instance of ImageLoader. For the code you posted in your question, the references look like this:
Suppose instead we implement loadImage without putting cache in the capture list:
class ImageLoader {
private let cache = Cache<URL, Image>()
func loadImage(
from url: URL,
then handler: #escaping (Result<Image, Error>) -> Void
) {
request(url) { result in
// ^^^^^^^^^ no capture list
do {
let image = try result.decodedAsImage()
self.cache.insert(image, forKey: url)
// ^^^^^ we have to explicitly reference self instead
handler(.success(image))
} catch {
handler(.failure(error))
}
}
}
}
Then the references look like this:
[cache] capture is still a strong reference to the ImageLoader property but doesn't retain self. And that prolongs the lifetime of just the cache object while a strong reference to cache is held by that request(url) callback block - self can be dealloced even before the callback block is done, and cache can hang around a bit longer.
You only get a retain cycle if there is a loop of strong references A->B and B->A, or A->B->C and C->A etc. Here we have A->Cache and some block that A created but then hands off to url session retains Cache. so that's not a cycle A->Cache and request(url) completion handler also -> Cache. A is free to be dealloced, meaning Cache reference count would go from 2 to 1 and still be around while the url session downloads.

Capture a method weakly

Note: This question is basically the same as this one, but for Swift 4 or 5.
Say I have a class that captures a closure:
class CallbackHolder {
typealias Callback = (String) -> Void
var callback: Callback
init(_ callback: #escaping Callback) {
self.callback = callback
}
func useCallback() {
self.callback("Hi!")
}
}
This class simply holds a callback in a variable, and has a function that uses that callback.
Now, say I have a client class that owns such a callback holder. This class wants the callback holder to call one of its methods as the callback:
class Client {
func callback(string: String) {
print(string)
}
lazy var callbackOwner = CallbackOwner(callback: callback)
deinit {
print("deinit")
}
}
This class has a callback, a callback owner that calls that callback, and a deinit that prints something so that we know whether we have a retain cycle (no deinit = retain cycle).
We can test our setup with the following test function:
func test() {
Client().callbackOwner.useCallback()
}
We want the test function to print both Hi! and deinit, so that we know that the callback works, and that the client does not suffer from a retain cycle.
The above Client implementation does in fact have a retain cycle -- passing the callback method to the callback owner causes the owner to retain the client strongly, causing a cycle.
Of course, we can fix the cycle by replacing
lazy var callbackOwner = CallbackOwner(callback: callback)
with
lazy var callbackOwner = CallbackOwner(callback: { [weak self] in
self?.callback($0)
})
This works, but:
it is tedious (compare the amount of code we now need)
it is dangerous (every new client of my CallbackOwner class must remember to do it this way, even though the original way is completely valid syntax, otherwise they will get a retain cycle)
So I am looking for a better way. I would like to capture the callback weakly at the CallbackOwner, not at the client. That way, new clients don't have to be aware of the danger of the retain cycle, and they can use my CallbackOwner in the most intuitive way possible.
So I tried to change CallbackOwner's callback property to
weak var callback: Callback?
but of course, Swift only allows us to capture class types weakly, not closures or methods.
At the time when this answer was written, there did not seem to be a way to do achieve what I'm looking for, but that was over 4 years ago. Has there been any developments in recent Swift versions that would allow me to pass a method to a closure-capturing object without causing a retain cycle?
Well one obvious way to do this would be to not hold a reference to CallbackHolder in Client i.e.
class Client {
func callback(string: String) {
print(string)
}
var callbackOwner: CallbackHolder { return CallbackHolder(callback) }
deinit {
print("deinit")
}
}
In the above case, I'd probably make CallbackHolder a struct rather than a class.
Personally, I don't see any value in wrapping the callback in a class at all. Just pass the callback around, or even Client. Maybe make a protocol for it to adhere to
protocol Callbackable
{
func callback(string: String)
}
extension Callbackable
{
func useCallback() {
self.callback(string: "Hi!")
}
}
class Client: Callbackable {
func callback(string: String) {
print(string)
}
deinit {
print("deinit")
}
}
func test(thing: Callbackable) {
thing.useCallback()
}
test(thing: Client())

Swift - Is checking whether a weak variable is nil or not thread-safe?

I have a process which runs for a long time and which I would like the ability to interrupt.
func longProcess (shouldAbort: #escaping ()->Bool) {
// Runs a long loop and periodically checks shouldAbort(),
// returning early if shouldAbort() returns true
}
Here's my class which uses it:
class Example {
private var abortFlag: NSObject? = .init()
private var dispatchQueue: DispatchQueue = .init(label: "Example")
func startProcess () {
let shouldAbort: ()->Bool = { [weak abortFlag] in
return abortFlag == nil
}
dispatchQueue.async {
longProcess(shouldAbort: shouldAbort)
}
}
func abortProcess () {
self.abortFlag = nil
}
}
The shouldAbort closure captures a weak reference to abortFlag, and checks whether that reference points to nil or to an NSObject. Since the reference is weak, if the original NSObject is deallocated then the reference that is captured by the closure will suddenly be nil and the closure will start returning true. The closure will be called repeatedly during the longProcess function, which is occurring on the private dispatchQueue. The abortProcess method on the Example class will be externally called from some other queue. What if someone calls abortProcess(), thereby deallocating abortFlag, at the exact same time that longProcess is trying to perform the check to see if abortFlag has been deallocated yet? Is checking myWeakReference == nil a thread-safe operation?
You can create the dispatched task as a DispatchWorkItem, which has a thread-safe isCancelled property already. You can then dispatch that DispatchWorkItem to a queue and have it periodically check its isCancelled. You can then just cancel the dispatched as such point you want to stop it.
Alternatively, when trying to wrap some work in an object, we’d often use Operation, instead, which encapsulates the task in its own class quite nicely:
class SomeLongOperation: Operation {
override func main() {
// Runs a long loop and periodically checks `isCancelled`
while !isCancelled {
Thread.sleep(forTimeInterval: 0.1)
print("tick")
}
}
}
And to create queue and add the operation to that queue:
let queue = OperationQueue()
let operation = SomeLongOperation()
queue.addOperation(operation)
And to cancel the operation:
operation.cancel()
Or
queue.cancelAllOperations()
Bottom line, whether you use Operation (which is, frankly, the “go-to” solution for wrapping some task in its own object) or roll-your-own with DispatchWorkItem, the idea is the same, namely that you don’t need to have your own state property to detect cancellation of the task. Both dispatch queues and operation queues already have nice mechanisms to simplify this process for you.
I saw this bug (Weak properties are not thread safe when reading SR-192) indicating that weak reference reads weren't thread safe, but it has been fixed, which suggests that (absent any bugs in the runtime), weak reference reads are intended to be thread safe.
Also interesting: Friday Q&A 2017-09-22: Swift 4 Weak References by Mike Ash

Closure outlives its created instance

Let's say I have a view controller, and in its viewDidLoad I am calling this function:
func callDataSource()
{
let dataSource = DataSource()
dataSource.callUber {
print("In viewDidLoad")
}
return
}
and this DataSource class is
class DataSource {
func callUber(withSuccess success: #escaping (() -> Void))
{
let uberManager = UberDataFetcher()
uberManager.getPrice {
print("In Data Source")
success()
}
return
}
}
And this UberDataFetcher is just a class that calls an Uber API. My question is: I have defined the DataSource object within the scope of the callDataSource function; this means that the object gets deallocated once that function returns. How does the completion block outlives the instance that has created it?
#escaping marks the closure as possibly outliving the context that created it. A closure is an object that has associated state (ie your capture list) along with a reference tot he function. Your Datasource retains the closure so it stays alive at least as long as the Datasource hangs on to it. Not that this might be a problem if your closure retained self, because then self would also last for at least as long as the closure lasts, which is as long as Datasource holds on to it.
The closure is an object for purposes of memory management. Referring to it in the UberDataFetcher's callback means that it is retained by that closure. So it is kept alive, along with anything that it captures, until the end of that scope.
let uberManager = UberDataFetcher()
uberManager.getPrice {
print("In Data Source")
success() // <--- Captured
} // <--- End of scope

How do I execute code once and only once in Swift?

The answers I've seen so far (1, 2, 3) recommend using GCD's dispatch_once thus:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
print("This is printed only on the first call to test()")
}
print("This is printed for each call to test()")
}
test()
Output:
This is printed only on the first call to test()
This is printed for each call to test()
But wait a minute. token is a variable, so I could easily do this:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
print("This is printed only on the first call to test()")
}
print("This is printed for each call to test()")
}
test()
token = 0
test()
Output:
This is printed only on the first call to test()
This is printed for each call to test()
This is printed only on the first call to test()
This is printed for each call to test()
So dispatch_once is of no use if we I can change the value of token! And turning token into a constant is not straightforward as it needs to of type UnsafeMutablePointer<dispatch_once_t>.
So should we give up on dispatch_once in Swift? Is there a safer way to execute code just once?
A man went to the doctor, and said "Doctor, it hurts when I stamp on my foot". The doctor replied, "So stop doing it".
If you deliberately alter your dispatch token, then yes - you'll be able to execute the code twice. But if you work around the logic designed to prevent multiple execution in any way, you'll be able to do it. dispatch_once is still the best method to ensure code is only executed once, as it handles all the (very) complex corner cases around initialisation and race conditions that a simple boolean won't cover.
If you're worried that someone might accidentally reset the token, you can wrap it up in a method and make it as obvious as it can be what the consequences are. Something like the following will scope the token to the method, and prevent anyone from changing it without serious effort:
func willRunOnce() -> () {
struct TokenContainer {
static var token : dispatch_once_t = 0
}
dispatch_once(&TokenContainer.token) {
print("This is printed only on the first call")
}
}
Static properties initialized by a closure are run lazily and at most once, so this prints only once, in spite of being called twice:
/*
run like:
swift once.swift
swift once.swift run
to see both cases
*/
class Once {
static let run: Void = {
print("Behold! \(__FUNCTION__) runs!")
return ()
}()
}
if Process.arguments.indexOf("run") != nil {
let _ = Once.run
let _ = Once.run
print("Called twice, but only printed \"Behold\" once, as desired.")
} else {
print("Note how it's run lazily, so you won't see the \"Behold\" text now.")
}
Example runs:
~/W/WhenDoesStaticDefaultRun> swift once.swift
Note how it's run lazily, so you won't see the "Behold" text now.
~/W/WhenDoesStaticDefaultRun> swift once.swift run
Behold! Once runs!
Called twice, but only printed "Behold" once, as desired.
I think the best approach is to just construct resources lazily as needed. Swift makes this easy.
There are several options. As already mentioned, you can initialize a static property within a type using a closure.
However, the simplest option is to define a global variable (or constant) and initialize it with a closure then reference that variable anywhere the initialization code is required to have happened once:
let resourceInit : Void = {
print("doing once...")
// do something once
}()
Another option is to wrap the type within a function so it reads better when calling. For example:
func doOnce() {
struct Resource {
static var resourceInit : Void = {
print("doing something once...")
}()
}
let _ = Resource.resourceInit
}
You can do variations on this as needed. For example, instead of using the type internal to the function, you can use a private global and internal or public function as needed.
However, I think the best approach is just to determine what resources you need to initialize and create them lazily as global or static properties.
For anyone who stumbles on this thread... We ran into a similar situation at Thumbtack and came up with this: https://www.github.com/thumbtack/Swift-RunOnce. Essentially, it lets you write the following
func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated: Bool)
runOnce {
// One-time code
}
}
I also wrote a blog post explaining how the code works, and explaining why we felt it was worth adding to our codebase.
I found this while searching for something similar: Run code once per app install. The above solutions only work within each app run. If you want to run something once across app launches, do this:
func runOnce() {
if UserDefaults.standard.object(forKey: "run_once_key") == nil {
UserDefaults.standard.set(true, forKey: "run_once_key")
/* run once code */
} else {
/* already ran one time */
}
}
If the app is deleted and re-installed, this will reset.
Use NSUbiquitousKeyValueStore for tracking a value across installs and devices as long as user using same appleID.