Break Swift closure retain circle with not weak explicit capture - swift

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.

Related

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())

How can I create a reference cycle using dispatchQueues?

I feel that I've always misunderstood that when reference cycles are created. Before I use to think that almost any where that you have a block and the compiler is forcing you to write .self then it's a sign that I'm creating a reference cycle and I need to use [weak self] in.
But the following setup doesn't create a reference cycle.
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution
class UsingQueue {
var property : Int = 5
var queue : DispatchQueue? = DispatchQueue(label: "myQueue")
func enqueue3() {
print("enqueued")
queue?.asyncAfter(deadline: .now() + 3) {
print(self.property)
}
}
deinit {
print("UsingQueue deinited")
}
}
var u : UsingQueue? = UsingQueue()
u?.enqueue3()
u = nil
The block only retains self for 3 seconds. Then releases it. If I use async instead of asyncAfter then it's almost immediate.
From what I understand the setup here is:
self ---> queue
self <--- block
The queue is merely a shell/wrapper for the block. Which is why even if I nil the queue, the block will continue its execution. They’re independent.
So is there any setup that only uses queues and creates reference cycles?
From what I understand [weak self] is only to be used for reasons other than reference cycles ie to control the flow of the block. e.g.
Do you want to retain the object and run your block and then release it? A real scenario would be to finish this transaction even though the view has been removed from the screen...
Or you want to use [weak self] in so that you can exit early if your object has been deallocated. e.g. some purely UI like stopping a loading spinner is no longer needed
FWIW I understand that if I use a closure then things are different ie if I do:
import PlaygroundSupport
import Foundation
PlaygroundPage.current.needsIndefiniteExecution
class UsingClosure {
var property : Int = 5
var closure : (() -> Void)?
func closing() {
closure = {
print(self.property)
}
}
func execute() {
closure!()
}
func release() {
closure = nil
}
deinit {
print("UsingClosure deinited")
}
}
var cc : UsingClosure? = UsingClosure()
cc?.closing()
cc?.execute()
cc?.release() // Either this needs to be called or I need to use [weak self] for the closure otherwise there is a reference cycle
cc = nil
In the closure example the setup is more like:
self ----> block
self <--- block
Hence it's a reference cycle and doesn't deallocate unless I set block to capturing to nil.
EDIT:
class C {
var item: DispatchWorkItem!
var name: String = "Alpha"
func assignItem() {
item = DispatchWorkItem { // Oops!
print(self.name)
}
}
func execute() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: item)
}
deinit {
print("deinit hit!")
}
}
With the following code, I was able to create a leak ie in Xcode's memory graph I see a cycle, not a straight line. I get the purple indicators. I think this setup is very much like how a stored closure creates leaks. And this is different from your two examples, where execution is never finished. In this example execution is finished, but because of the references it remains in memory.
I think the reference is something like this:
┌─────────┐─────────────self.item──────────────▶┌────────┐
│ self │ │workItem│
└─────────┘◀︎────item = DispatchWorkItem {...}───└────────┘
You say:
From what I understand the setup here is:
self ---> queue
self <--- block
The queue is merely a shell/wrapper for the block. Which is why even if I nil the queue, the block will continue its execution. They’re independent.
The fact that self happens to have a strong reference to the queue is inconsequential. A better way of thinking about it is that a GCD, itself, keeps a reference to all dispatch queues on which there is anything queued. (It’s analogous to a custom URLSession instance that won’t be deallocated until all tasks on that session are done.)
So, GCD keeps reference to the queue with dispatched tasks. The queue keeps a strong reference to the dispatched blocks/items. The queued block keeps a strong reference to any reference types they capture. When the dispatched task finishes, it resolves any strong references to any captured reference types and is removed from the queue (unless you keep your own reference to it elsewhere.), generally thereby resolving any strong reference cycles.
Setting that aside, where the absence of [weak self] can get you into trouble is where GCD keeps a reference to the block for some reason, such as dispatch sources. The classic example is the repeating timer:
class Ticker {
private var timer: DispatchSourceTimer?
func startTicker() {
let queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".ticker")
timer = DispatchSource.makeTimerSource(queue: queue)
timer!.schedule(deadline: .now(), repeating: 1)
timer!.setEventHandler { // whoops; missing `[weak self]`
self.tick()
}
timer!.resume()
}
func tick() { ... }
}
Even if the view controller in which I started the above timer is dismissed, GCD keeps firing this timer and Ticker won’t be released. As the “Debug Memory Graph” feature shows, the block, created in the startTicker routine, is keeping a persistent strong reference to the Ticker object:
This is obviously resolved if I use [weak self] in that block used as the event handler for the timer scheduled on that dispatch queue.
Other scenarios include a slow (or indefinite length) dispatched task, where you want to cancel it (e.g., in the deinit):
class Calculator {
private var item: DispatchWorkItem!
deinit {
item?.cancel()
item = nil
}
func startCalculation() {
let queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".calcs")
item = DispatchWorkItem { // whoops; missing `[weak self]`
while true {
if self.item?.isCancelled ?? true { break }
self.calculateNextDataPoint()
}
self.item = nil
}
queue.async(execute: item)
}
func calculateNextDataPoint() {
// some intense calculation here
}
}
All of that having been said, in the vast majority of GCD use-cases, the choice of [weak self] is not one of strong reference cycles, but rather merely whether we mind if strong reference to self persists until the task is done or not.
If we’re just going to update the the UI when the task is done, there’s no need to keep the view controller and its views in the hierarchy waiting some UI update if the view controller has been dismissed.
If we need to update the data store when the task is done, then we definitely don’t want to use [weak self] if we want to make sure that update happens.
Frequently, the dispatched tasks aren’t consequential enough to worry about the lifespan of self. For example, you might have a URLSession completion handler dispatch UI update back to the main queue when the request is done. Sure, we theoretically would want [weak self] (as there’s no reason to keep the view hierarchy around for a view controller that’s been dismissed), but then again that adds noise to our code, often with little material benefit.
Unrelated, but playgrounds are a horrible place to test memory behavior because they have their own idiosyncrasies. It’s much better to do it in an actual app. Plus, in an actual app, you then have the “Debug Memory Graph” feature where you can see the actual strong references. See https://stackoverflow.com/a/30993476/1271826.

Accessing Singletons in a Closure = Memory Leak?

Does accessing a singleton within a closure cause a retain cycle?
Specifically something like this example:
class TheSingleton
{
static let shared = TheSingleton() //THE SINGLETON
enum Temperature //An associated enum
{
case cold, hot
}
var currentTemp: Temperature? //A non-class-type variable
var aPicture: UIImage? //A class-type variable
func giveMeFive() -> Int //A function
{
return 5
}
//Pay attention to this
func doSomething(onDone: #escaping (Int) -> ())
{
OtherSVC.upload("Mr. Server, do async stuff plz") { (inImage) in
TheSingleton.shared.currentTemp = .cold
TheSingleton.shared.aPicture = inImage
onDone(TheSingleton.shared.giveMeFive())
}
}
}
//Fire the thing
TheSingleton.shared.doSomething { _ in}
If so, I don't really know how to write a capture list for this...
[weak TheSingleton.shared] (inImage) in
You can't do that ^
I included three cases because maybe the type of data matters?
I think I'm missing some fundamentals on capture lists and closure retain cycles.
All I know is whenever you access something outside of a closure's curly braces, you have to unown/weak it if it's a class-type object.
That's because closures create strong references by default.
I thought I could be cheeky and get around retain cycles by calling the entire singleton in closures, but I'm probably being dumb by turning a blind eye.
Would a solution be to do something like:
var updateDis = TheSingleton.shared.aPicture
OtherSVC.upload("ugh this is lame, and more work") { [unowned updateDis] inPic in
updateDis = inPic
}
?
Since you are writing a singleton, TheSingleton.shared is pretty much always going to be the same thing as self, so capture unowned self or weak self instead. I would prefer weak here because self will pretty much always be retained by the class and will only be deallocated when the application terminates.
OtherSVC.upload("Mr. Server, do async stuff plz") { [unowned self] (inImage) in
self..currentTemp = .cold
self.aPicture = inImage
onDone(self.giveMeFive())
}

"Closure cannot implicitly capture a mutating self parameter" - after updating to Swift 3 [duplicate]

I am using Firebase to observe event and then setting an image inside completion handler
FirebaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.img = UIImage(named:"Some-image")!
} else {
self.img = UIImage(named: "some-other-image")!
}
})
However I am getting this error
Closure cannot implicitly capture a mutating self parameter
I am not sure what this error is about and searching for solutions hasn't helped
The short version
The type owning your call to FirebaseRef.observeSingleEvent(of:with:) is most likely a value type (a struct?), in which case a mutating context may not explicitly capture self in an #escaping closure.
The simple solution is to update your owning type to a reference once (class).
The longer version
The observeSingleEvent(of:with:) method of Firebase is declared as follows
func observeSingleEvent(of eventType: FIRDataEventType,
with block: #escaping (FIRDataSnapshot) -> Void)
The block closure is marked with the #escaping parameter attribute, which means it may escape the body of its function, and even the lifetime of self (in your context). Using this knowledge, we construct a more minimal example which we may analyze:
struct Foo {
private func bar(with block: #escaping () -> ()) { block() }
mutating func bax() {
bar { print(self) } // this closure may outlive 'self'
/* error: closure cannot implicitly capture a
mutating self parameter */
}
}
Now, the error message becomes more telling, and we turn to the following evolution proposal was implemented in Swift 3:
SE-0035: Limiting inout capture to #noescape contexts
Stating [emphasis mine]:
Capturing an inout parameter, including self in a mutating
method, becomes an error in an escapable closure literal, unless the
capture is made explicit (and thereby immutable).
Now, this is a key point. For a value type (e.g. struct), which I believe is also the case for the type that owns the call to observeSingleEvent(...) in your example, such an explicit capture is not possible, afaik (since we are working with a value type, and not a reference one).
The simplest solution to this issue would be making the type owning the observeSingleEvent(...) a reference type, e.g. a class, rather than a struct:
class Foo {
init() {}
private func bar(with block: #escaping () -> ()) { block() }
func bax() {
bar { print(self) }
}
}
Just beware that this will capture self by a strong reference; depending on your context (I haven't used Firebase myself, so I wouldn't know), you might want to explicitly capture self weakly, e.g.
FirebaseRef.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in ...
Sync Solution
If you need to mutate a value type (struct) in a closure, that may only work synchronously, but not for async calls, if you write it like this:
struct Banana {
var isPeeled = false
mutating func peel() {
var result = self
SomeService.synchronousClosure { foo in
result.isPeeled = foo.peelingSuccess
}
self = result
}
}
You cannot otherwise capture a "mutating self" with value types except by providing a mutable (hence var) copy.
Why not Async?
The reason this does not work in async contexts is: you can still mutate result without compiler error, but you cannot assign the mutated result back to self. Still, there'll be no error, but self will never change because the method (peel()) exits before the closure is even dispatched.
To circumvent this, you may try to change your code to change the async call to synchronous execution by waiting for it to finish. While technically possible, this probably defeats the purpose of the async API you're interacting with, and you'd be better off changing your approach.
Changing struct to class is a technically sound option, but doesn't address the real problem. In our example, now being a class Banana, its property can be changed asynchronously who-knows-when. That will cause trouble because it's hard to understand. You're better off writing an API handler outside the model itself and upon finished execution fetch and change the model object. Without more context, it is hard to give a fitting example. (I assume this is model code because self.img is mutated in the OP's code.)
Adding "async anti-corruption" objects may help
I'm thinking about something among the lines of this:
a BananaNetworkRequestHandler executes requests asynchronously and then reports the resulting BananaPeelingResult back to a BananaStore
The BananaStore then takes the appropriate Banana from its inside by looking for peelingResult.bananaID
Having found an object with banana.bananaID == peelingResult.bananaID, it then sets banana.isPeeled = peelingResult.isPeeled,
finally replacing the original object with the mutated instance.
You see, from the quest to find a simple fix it can become quite involved easily, especially if the necessary changes include changing the architecture of the app.
If someone is stumbling upon this page (from search) and you are defining a protocol / protocol extension, then it might help if you declare your protocol as class bound. Like this:
protocol MyProtocol: class {
...
}
You can try this! I hope to help you.
struct Mutating {
var name = "Sen Wang"
mutating func changeName(com : #escaping () -> Void) {
var muating = self {
didSet {
print("didSet")
self = muating
}
}
execute {
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 15, execute: {
muating.name = "Wang Sen"
com()
})
}
}
func execute(with closure: #escaping () -> ()) { closure() }
}
var m = Mutating()
print(m.name) /// Sen Wang
m.changeName {
print(m.name) /// Wang Sen
}
Another solution is to explicitly capture self (since in my case, I was in a mutating function of a protocol extension so I couldn't easily specify that this was a reference type).
So instead of this:
functionWithClosure(completion: { _ in
self.property = newValue
})
I have this:
var closureSelf = self
functionWithClosure(completion: { _ in
closureSelf.property = newValue
})
Which seems to have silenced the warning.
Note this does not work for value types so if self is a value type you need to be using a reference type wrapper in order for this solution to work.

Object resurrection when using C callbacks from 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