Accessing Singletons in a Closure = Memory Leak? - swift

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

Related

Memory semantics when capturing values directly in closures

I've recently read about capture lists in this article of objc.io. I think it is a great tip and I'm started to use it.
Although it is not totally clarified, I assume there are no retain cycles when capturing this way, so you get a captured strong reference but with no retain cycle to be worried about.
And I've realized that it is possible to even capture methods, not only values:
.subscribe(onNext: { [showErrorAlert, populate] result in
switch result {
case .success(let book):
populate(book)
case .error(_):
showErrorAlert(L10n.errorExecutingOperation.localized)
}
})
I am trying to find some documentation related to this way of capturing but I cannot find any. Is this practice safe? Is this equal to the usual dance of [weak self], strongSelf = self inside the closure?
Is this practice safe? Is this equal to the usual dance of [weak
self], strongSelf = self inside the closure?
Yes and no - capturing methods of objects retains the object as well. The captured method could be accessing anything from the instance so it makes sense that it retains it.
On the other hand capturing a property does not retain the instance.
Here is a short snippet you can paste in playground to see for yourself:
import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
class A {
let name: String
init(name: String) {
self.name = name
}
func a() {
print("Hello from \(name)")
}
func scheduleCaptured() {
print("Scheduling captured method")
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { [a] in
a()
}
}
func scheduleCapturedVariable() {
print("Scheduling captured variable")
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { [name] in
print("Hello from \(name)")
}
}
deinit {
print("\(name) deinit")
}
}
var a1: A? = A(name: "instance 1")
a1?.scheduleCapturedVariable()
var a2: A? = A(name: "instance 2")
a2?.scheduleCaptured()
a1 = nil
a2 = nil
The output is:
Scheduling captured variable
Scheduling captured method
instance 1 deinit
Hello from instance 1
Hello from instance 2
instance 2 deinit
You can see that instance 2 is not deinitialised until the captured block is fired, while instance 1 is deinitialised immediately after set to nil.
Capturing instance methods isn't safe unless you're sure your closure will be disposed before deinit (f.e. you absolutely sure it will trigger limited amount of times and then sequence always ends). Same for non-reactive use-cases.
The method is captured strongly(and can't be captured weakly), so the closure would keep the reference, prohibiting ARC from destroying it. Hence with strongSelf behavior closure keep only weak ref to object, binds it as strong on execution start, and then releases strong reference at the execution end.

"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.

Why Swift closure not capture self?

I was testing swift closure with Xcode playground.
This is my code:
import UIKit
class A{
var closure: ()->() = {}
var name: String = "A"
init() {
self.closure = {
self.name = self.name + " Plus"
}
}
deinit {
print(name + " is deinit")
}
}
var a: A?
a = A()
a = nil
As what is expected, a is self contained by closure, so a is never released.
But, when I add this line before the last line:
a?.closure = { a?.name = "ttt" }
Then, I found "A is deinit" in the output window, which means a is released.
Why? is a not recycle reference?
To be test, I use a function to set the closure, which the code is version 2:
import UIKit
class A{
var closure: ()->() = {}
func funcToSetClosure(){
self.closure = { self.name = "BBB"}
}
var name: String = "A"
init() {
self.closure = {
self.name = self.name + " Plus"
}
}
deinit {
print(name + " is deinit")
}
}
var a: A?
a = A()
a?.funcToSetClosure()
a = nil
Again, a is never released.
So I got the conclusion, when closure is set by init or a function in the class, it will cause recycle reference, when it is set out side the class, it will not cause recycle reference. Am I right?
There are retain cycles in both cases. The difference is the nature of the reference, not the place where closure is set. This difference is manifested in what it takes to break the cycle:
In the "inside" situation, the reference inside the closure is self. When you release your reference to a, that is insufficient to break the cycle, because the cycle is directly self-referential. To break the cycle, you would have had also to set a.closure to nil before setting a to nil, and you didn't do that.
In the "outside" situation, the reference is a. There is a retain cycle so long as your a reference is not set to nil. But you eventually do set it to nil, which is sufficient to break the cycle.
(Illustrations come from Xcode's memory graph feature. So cool.)
As the SIL documentation says, when you capture a local variable in a closure, it will be stored on the heap with reference counting:
Captured local variables and the payloads of indirect value types are
stored on the heap. The type #box T is a reference-counted type that
references a box containing a mutable value of type T.
Therefore when you say:
var a : A? = A()
a?.closure = { a?.name = "ttt" }
you do have a reference cycle (which you can easily verify). This is because the instance of A has a reference to the closure property, which has a reference to the heap-allocated boxed A? instance (due to the fact that it's being captured by the closure), which in turn has a reference to the instance of A.
However, you then say:
a = nil
Which sets the heap-allocated boxed A? instance's value to .none, thus releasing its reference to the instance of A, therefore meaning that you no longer have a reference cycle, and thus A can be deallocated.
Just letting a fall out of scope without assigning a = nil will not break the reference cycle, as the instance of A? on the heap is still being retained by the closure property of A, which is still being retained by the A? instance.
What causes the retain cycle is that you reference self in the closure.
var a: A?
a = A()
a?.closure = { a?.name = "ttt" }
a = nil
You change the closure to no longer reference self, that's why it is deallocated.
In the final example, you make it reference self again in the closure, that is why it does not deallocate. There are ways around this, this post is a great list of when to use each case in swift: How to Correctly handle Weak Self in Swift Blocks with Arguments
I would imagine you are looking for something like this, where you use a weak reference to self inside the block. Swift has some new ways to do this, most commonly using the [unowned self] notation at the front of the block.
init() {
self.closure = { [unowned self] in
self.name = self.name + " Plus"
}
}
More reading on what is going on here: Shall we always use [unowned self] inside closure in Swift

Swift Memory Management for Recursive Protocols

Consider the following Class in swift that maintains a recursive relationship with itself
class OctupPromisable {
var promise: OctupPromisable?
weak var chainedPromise: OctupPromisable?
func then(octupPromisable: OctupPromisable) -> OctupPromisable? {
self.promise = octupPromisable
octupPromisable.chainedPromise = self
return self.promise
}
func start() {
if nil == self.chainedPromise {
self.fire(nil)
}else {
self.chainedPromise!.start()
}
}
}
used as such:
OctupPromisable()
.then(OctupPromisable())
.then(OctupPromisable())
.start()
when I call start with the chainedPromise being weak, it always results in the chainedPromise being nil and hence the start method never recurses.
Making the chainedPromise strong, causes the start method to recurse and work correctly. But in doing so am I not creating a strong cyclic relationship that leads to memory leak? If so, what can be done in order to achieve the recursion and yet avoid memory leak?
Thanks!
Make your chained process strong, but after you've used it, set it to nil. You're done with it, so you don't need to hold a strong reference any more. If there are no other strong references, the object will be deallocated.
If you don't need to keep references after execution, you could use a strong reference and release inner promises recursively, so when your first promise deallocate, it will not cause a memory leak.
I couldn't test the code but it goes like this:
class OctupPromisable {
weak var promise: OctupPromisable? // Make it weak to avoid reference cycle
var chainedPromise: OctupPromisable? // Make it a strong reference
func start() {
if nil == self.chainedPromise {
self.fire(nil)
} else {
self.chainedPromise!.start()
self.chainedPromise = nil // Will be deallocated after all 'start' calls
}
}
}

Avoiding retain cycle when using function as a block in swift

following is a code sample you can run in a playground
import Foundation
class TempNotifier {
var onChange: (Int) -> Void = {t in }
var currentTemp = 72
init() {
// 1.
onChange = { [unowned self] temp in
self.currentTemp = temp
}
// 2.
onChange = {[unowned self] temp in
self.tempHandler(temp)
}
// 3.
unowned let s = self
onChange = s.tempHandler
}
deinit {
println("deinit")
}
private func tempHandler(temp: Int) {
self.currentTemp = temp
}
}
var tN: TempNotifier? = TempNotifier()
tN = nil
It illustrates 3 ways of assigning a value to a block with potential retain-cycle. Case 1. and 2. create no retain cycle due to unowned self however in case 3. it seems like there is no way to break the retain cycle (deinit is never printed). As you can see, I even tried to create a local unowned reference.
Is this the desired behaviour, is it "by design"? Or am I missing something?
Thanks!
Cross-posted from https://devforums.apple.com/message/1122247
Yes, this is the designed behavior.
Accessing a method without calling it, like s.tempHandler, is equivalent to a closure expression like { x in s.tempHandler(x) }. Here s is not marked unowned or weak, and hence is retained by the closure. If you want it to be captured as unowned or weak, you must explicitly write out the closure.