Unowned self in a closure in a closure - swift

If I have a closure in another closure is it enough to use unowned/weak once in the outer closure to avoid retain cycles?
Example:
foo.aClosure({[unowned self] (allowed: Bool) in
if allowed {
self.doStuff()
self.something.anotherClosure({ (s:String) -> (Void) in
self.doSomethingElse(s)
})
}
})

Only declaring weak or unowned self in the capture list of the outer closure is enough to avoid retain cycles if you don't create a strong reference to self within the outer closure (e.g. by doing: guard let strongSelf = self else { return }).
If you do create a strong reference within the closure, you must add a capture list to the inner closure to ensure that it captures your strong reference to self weakly.
Here are some examples:
import Foundation
import PlaygroundSupport
class SomeObject {
typealias OptionalOuterClosure = ((Int) -> Void)?
typealias InnerClosure = () -> Void
var outerClosure: OptionalOuterClosure
func setup() {
// Here are several examples of the outer closure that you can easily switch out below
// All of these outer closures contain inner closures that need references to self
// optionalChecks
// - has a capture list in the outer closure
// - uses the safe navigation operator (?) to ensure that self isn't nil
// this closure does NOT retain self, so you should not see the #2 calls below
let optionalChecks: OptionalOuterClosure = { [weak self] callNumber in
print("outerClosure \(callNumber)")
self?.delayCaller { [weak self] in
print("innerClosure \(callNumber)")
self?.doSomething(callNumber: callNumber)
}
}
// copiedSelfWithInnerCaptureList
// - has a capture list in the outer closure
// - creates a copy of self in the outer closure called strongSelf to ensure that self isn't nil
// - has a capture list in the inner closure
// - uses the safe navigation operator (?) to ensure strongSelf isn't nil
// this closure does NOT retain self, so you should not see the #2 calls below
let copiedSelfWithInnerCaptureList: OptionalOuterClosure = { [weak self] callNumber in
guard let strongSelf = self else { return }
print("outerClosure \(callNumber)")
strongSelf.delayCaller { [weak strongSelf] in
print("innerClosure \(callNumber)")
strongSelf?.doSomething(callNumber: callNumber)
}
}
// copiedSelfWithoutInnerCaptureList
// - has a capture list in the outer closure
// - creates a copy of self in the outer closure called strongSelf to ensure that self isn't nil
// - does NOT have a capture list in the inner closure and does NOT use safe navigation operator
// this closure DOES retain self, so you should see the doSomething #2 call below
let copiedSelfWithoutInnerCaptureList: OptionalOuterClosure = { [weak self] callNumber in
guard let strongSelf = self else { return }
print("outerClosure \(callNumber)")
strongSelf.delayCaller {
print("innerClosure \(callNumber)")
strongSelf.doSomething(callNumber: callNumber)
}
}
// retainingOuterClosure
// - does NOT have any capture lists
// this closure DOES retain self, so you should see the doSomething #2 call below
let retainingOuterClosure: OptionalOuterClosure = { callNumber in
print("outerClosure \(callNumber)")
self.delayCaller {
print("innerClosure \(callNumber)")
self.doSomething(callNumber: callNumber)
}
}
// Modify which outerClosure you would like to test here
outerClosure = copiedSelfWithInnerCaptureList
}
func doSomething(callNumber: Int) {
print("doSomething \(callNumber)")
}
func delayCaller(closure: #escaping InnerClosure) {
delay(seconds: 1, closure: closure)
}
deinit {
print("deinit")
}
}
// Handy delay method copied from: http://alisoftware.github.io/swift/closures/2016/07/25/closure-capture-1/
func delay(seconds: Int, closure: #escaping () -> Void) {
let time = DispatchTime.now() + .seconds(seconds)
DispatchQueue.main.asyncAfter(deadline: time) {
print("🕑")
closure()
}
}
var someObject: SomeObject? = SomeObject()
someObject?.setup()
// Keep a reference to the outer closure so we can later test if it retained someObject
let copiedOuterClosure = someObject!.outerClosure!
// Call the outer closure once just to make sure it works
copiedOuterClosure(1)
// Wait a second before we destroy someObject to give the first call a chance to work
delay(seconds: 1) {
// Run the outerClosure again to check if we retained someObject
copiedOuterClosure(2)
// Get rid of our reference to someObject before the inner closure runs
print("de-referencing someObject")
someObject = nil
}
// Keep the main run loop going so our async task can complete (need this due to how playgrounds work)
PlaygroundPage.current.needsIndefiniteExecution = true

Yes, however I would use weak over unowned because self.doStuff() with throw an exception if nil while if you use weak and its self?.doStuff() there won't be an exception thrown and it just won't execute.
You can test this in the playground with the following code:
typealias Closure = () -> Void
class ClosureObject {
var closure:Closure?
func saveClosure(closure:Closure?) {
self.closure = closure
}
}
let mainClosureObject = ClosureObject()
class TestObject {
let closureObject = ClosureObject()
func log() {
print("logged")
}
func run() {
mainClosureObject.saveClosure() {[weak self] in
self?.closureObject.saveClosure() {
self?.log()
}
}
}
}
var testObject:TestObject? = TestObject()
let closureObject = testObject?.closureObject
testObject?.run()
mainClosureObject.closure?()
closureObject?.closure?()
testObject = nil
closureObject?.closure?()
mainClosureObject.closure?()
closureObject?.closure?()
and compare it with:
typealias Closure = () -> Void
class ClosureObject {
var closure:Closure?
func saveClosure(closure:Closure?) {
self.closure = closure
}
}
let mainClosureObject = ClosureObject()
class TestObject {
let closureObject = ClosureObject()
func log() {
print("logged")
}
func run() {
mainClosureObject.saveClosure() {
self.closureObject.saveClosure() {
self.log()
}
}
}
}
var testObject:TestObject? = TestObject()
let closureObject = testObject?.closureObject
testObject?.run()
mainClosureObject.closure?()
closureObject?.closure?()
testObject = nil
closureObject?.closure?()
mainClosureObject.closure?()
closureObject?.closure?()

Related

Do we need to repeat `guard let self = self else { return }` inside each nested closure to keep strong self?

I need to keep strong self inside my inner clousures.
I know that it's enough to declare [weak self] only once for outer closure.
But what about guard let self = self else { return }, is it enough to declare it once for outer closure also? Do we have any edge cases here ?
apiManager.doSomething(user: user) { [weak self] result in
guard let self = self else { return }
self.storageManager.doSomething(user: user) { result in
// guard let self = self else { return } <- DO WE NEED IT HERE ?
self.doSomething()
}
}
Seems like language analyser says NO - one declaration is enough , but want to be sure.
Yes, one is enough.
If you write
guard let self = self else { return }
you'll create a new local variable that will hold a strong reference to the outside weak self.
It's the same as writing
guard let strongSelf = self else { return }
and then use strongSelf for the rest of the block.
Update Swift 5.7
You don't need a new guard in doSomething(user:), when that method works synchronously.
With Swift 5.7, you can use the rewrite syntax guard let self else
apiManager.doSomething(user: user) { [weak self] result in
guard let self else { return }
self.storageManager.doSomething(user: user) { result in
// You don't a new guard here, when doSomething works synchronously
self.doSomething()
}
}
But, when your guard only returns, than you could also write it so:
Same behaviour.
apiManager.doSomething(user: user) { [weak self] _ in
self?.storageManager.doSomething(user: user) { _ in
self?.doSomething()
}
}
No, in short you do not need that. If you outer closure uses [weak self] then you should not worry about the inner closure as it will already have a weak reference to self. On the other hand if your outer closure is not using [weak self] it is reasonable to put it for the inside block. A more detailed explation can be found here.
The safest approach is to use [weak self] 2 times in both outter and inner closure.
There is edge case, where using [weak self] 1 time will cause memory leak.
Consider the following escaping closure case, which keeps reference to closures (Example copied from https://stackoverflow.com/a/62352667/72437)
import UIKit
public class CaptureListExperiment {
public init() {
}
var _someFunctionWithTrailingClosure: (() -> ())?
var _anotherFunctionWithTrailingClosure: (() -> ())?
func someFunctionWithTrailingClosure(closure: #escaping () -> ()) {
print("starting someFunctionWithTrailingClosure")
_someFunctionWithTrailingClosure = closure
DispatchQueue.global().asyncAfter(deadline: .now() + 1) { [weak self] in
self?._someFunctionWithTrailingClosure!()
print("finishing someFunctionWithTrailingClosure")
}
}
func anotherFunctionWithTrailingClosure(closure: #escaping () -> ()) {
print("starting anotherFunctionWithTrailingClosure")
_anotherFunctionWithTrailingClosure = closure
DispatchQueue.global().asyncAfter(deadline: .now() + 1) { [weak self] in
self?._anotherFunctionWithTrailingClosure!()
print("finishing anotherFunctionWithTrailingClosure")
}
}
func doSomething() {
print("doSomething")
}
public func testCompletionHandlers() {
someFunctionWithTrailingClosure { [weak self] in
guard let self = self else { return }
self.anotherFunctionWithTrailingClosure {
self.doSomething()
}
}
}
// go ahead and add `deinit`, so I can see when this is deallocated
deinit {
print("deinit")
}
}
func performExperiment() {
let obj = CaptureListExperiment()
obj.testCompletionHandlers()
Thread.sleep(forTimeInterval: 1.3)
}
performExperiment()
/* Output:
starting someFunctionWithTrailingClosure
starting anotherFunctionWithTrailingClosure
finishing someFunctionWithTrailingClosure
doSomething
finishing anotherFunctionWithTrailingClosure
*/
Since, this kind of edge case is very hard to spot. I think using [weak self] 2 times, will be the safest approach and common pattern, without causing developer much headache.

Add [unowned self] to the closure argument Swift

I have a function with a completion handler, returning one parameter or more.
In a client, when executing a completion handler, I'd like to have an unowned reference to self, as well as having access to the parameter passed.
Here is the Playground example illustrating the issue and the goal I'm trying to achieve.
import UIKit
struct Struct {
func function(completion: (String) -> ()) {
completion("Boom!")
}
func noArgumentsFunction(completion: () -> Void) {
completion()
}
}
class Class2 {
func execute() {
Struct().noArgumentsFunction { [unowned self] in
//...
}
Struct().function { (string) in // Need [unowned self] here
//...
}
}
}
As I said in my comment
Struct().function { [unowned self] (string) in
//your code here
}
Capture list and closure parameters that should be the order in closures more info from Apple Documentation
Defining a Capture List
Each item in a capture list is a pairing of
the weak or unowned keyword with a reference to a class instance (such
as self) or a variable initialized with some value (such as delegate =
self.delegate!). These pairings are written within a pair of square
braces, separated by commas.
Place the capture list before a closure’s parameter list and return
type if they are provided:
lazy var someClosure: (Int, String) -> String = {
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
// closure body goes here
}
If a closure does not specify a parameter list or return type because
they can be inferred from
context, place the capture list at the very start of the closure,
followed by the in keyword:
lazy var someClosure: () -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
}
Is it just the syntax for including [unowned self] in the closure parameter list you need?
struct Struct {
func function(completion:(String)->()) {
completion("Boom!")
}
}
class Class {
func execute() {
Struct().function { [unowned self] string in
print(string)
print(self)
}
}
}
Class().execute()

Does using a function as a closure retain self?

I'm having trouble tracking down a retain cycle. I think it's to do with the way I subscribe to events. Pseudo code is like this:
override func viewDidLoad() {
func handleEvent() {
self.doSomething()
}
subscribe("eventName", block: handleEvent)
}
deinit {
unsubscribe("eventName")
}
Will this create a retain cycle to self / my ViewController? And if so, how can I get around it? If I was using a closure, I could use [weak self], but since I'm passing a function, is there anyway to use a [weak self] equivalent?
Long story short, your code does retain a reference. (handleEvent->viewDidLoad->self), http://blog.xebia.com/function-references-in-swift-and-retain-cycles/ has some general strategies to avoid the issue. My recommendation would be to create a function reference, rather than declaring a function:
let eventHandler: () -> () = { [weak self] in
self?.doSomething()
}
subscribe("eventName", block: eventHandler)
If you reference a property or method from inside your class it'll create a retain cycle.
class SomeClass {
val a: (block: (() -> ()) -> ()) = ...
func run() {
func b() {
print("Hello, World!")
}
func c() {
self.someMethod()
}
func d() { [weak self]
self?.someMethod()
}
a(block: b) // no retain cycle
a(block: c) // retain cycle
a(block: d) // no retain cycle
}
func someMethod() {
print("Hello, World!")
}
}

Weak or Unowned in this example?

I have a code like this:
open class WebServiceOperation: Operation {
public init(dependencies: [Operation]? = nil, finishBlock: ((_ operation: WebServiceOperation) -> Void)? = nil) {
super.init()
completionBlock = { [weak self, finishBlock] in
guard let `self` = self, self.isCancelled == false else { return }
DispatchQueue.main.sync {
finishBlock?(self)
}
}
// ...
}
}
I was wondering if I should use unowned instead of weak in completionBlock.
First - completionBlock is a block that is executed only by Operation object itself, so self inside it will not be nil. Thats why it could be unowned. But later self it's passed to finishBlock?() as a parameter. This will retain self for that finishBlock. Also this passing is done in DispatchQueue.main.sync block, which should also retain self.
So is it safe and correct to use unowned self in completionBlock instead of weak?

Do capture lists of inner closures need to redeclare `self` as `weak` or `unowned`?

If I have a closure passed to a function like this:
someFunctionWithTrailingClosure { [weak self] in
anotherFunctionWithTrailingClosure { [weak self] in
self?.doSomething()
}
}
If I declare self as [weak self] in someFunctionWithTrailingClosure's capture list without redeclaring it as weak again in the capture list of anotherFunctionWithTrailingClosure self is already becoming an Optional type but is it also becoming a weak reference as well?
Thanks!
The [weak self] in anotherFunctionWithTrailingClosure is not needed.
You can empirically test this:
class Experiment {
func someFunctionWithTrailingClosure(closure: #escaping () -> Void) {
print("starting", #function)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
closure()
print("finishing", #function)
}
}
func anotherFunctionWithTrailingClosure(closure: #escaping () -> Void) {
print("starting", #function)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
closure()
print("finishing", #function)
}
}
func doSomething() {
print(#function)
}
func testCompletionHandlers() {
someFunctionWithTrailingClosure { [weak self] in
self?.anotherFunctionWithTrailingClosure { // [weak self] in
self?.doSomething()
}
}
}
// go ahead and add `deinit`, so I can see when this is deallocated
deinit {
print("deinit")
}
}
And then:
func performExperiment() {
DispatchQueue.global().async {
let obj = Experiment()
obj.testCompletionHandlers()
// sleep long enough for `anotherFunctionWithTrailingClosure` to start, but not yet call its completion handler
Thread.sleep(forTimeInterval: 1.5)
}
}
If you do this, you will see that doSomething is never called and that deinit is called before anotherFunctionWithTrailingClosure calls its closure.
That having been said, I might still be inclined to use the [weak self] syntax on anotherFunctionWithTrailingClosure to make my intent explicit.
TL;DR
Although using [weak self] once in the outer block is fine (EX1), if you change this reference to strong (e.g. guard let self = self), you'll need a [weak self] in the inner block as well (EX3).
Also using [weak self] only once on the inner block is typically an error (EX2_B). Unfortunately, this is a common mistake to make when refactoring code, and can be hard-to-spot when it is made.
A good rule of thumb is to always use weak if the object is strong immediately outside of the closure.
Examples that don't retain self (i.e. typically these are the "good" scenarios):
// EX1
fn { [weak self] in
self?.foo()
}
// EX2
fn { [weak self] in
fn2 {
self?.foo()
}
}
// self is weak inside fn, thus adding an extra `[weak self]` inside fn2 is unnecessary
// EX3
fn { [weak self] in
guard let self = self else { return }
fn2 { [weak self] in
self?.foo()
}
}
Examples that DO retain self (i.e. typically the "bad" scenarios):
// EX1_B
fn {
self.foo()
}
// fn retains self
// EX2_B
fn {
fn2 { [weak self] in
self.foo()
}
}
// fn retains self (this is a common, hard-to-spot mistake)
// EX3_B
fn { [weak self] in
guard let self = self else { return }
fn2 {
self.foo()
}
}
// fn2 retains self
As Hamish alludes to, there are two main reasons weak is useful:
To prevent retain cycles.
To prevent objects living longer than they should be.
More on #2 (preventing long lived objects)
In Rob's example, the function is not retaining the closure (beyond dispatch_async which is all but guaranteed to fire the closure at some point in the future), thus you'll never end up with a retain cycle. So using weak in this case, then, is to prevent #2 from happening.
As Hamish mentions, weak is not actually needed in this example to prevent retain cycles, as there are no retain cycles. weak, in this case, is used to prevent an object living longer than needed. It depends entirely on your use-case as to when you consider an object living longer than needed. Thus there are times when you would want to use weak only outside (EX2), and other times when you would want to use the weak outer, strong inner, weak inner dance (EX3), for example.
More on #1 (preventing retain cycles)
To examine the retain cycle problem, let's say a function is storing a reference to the block (i.e. heap) instead of referencing the function directly (i.e. stack). Many times we don't know the internals of a class/function, so it's safer to assume that the function is retaining the block.
Now you can easily create a retain cycle using weak outer, and only using strong inner (EX3_B):
public class CaptureListExperiment {
public init() {
}
var _someFunctionWithTrailingClosure: (() -> ())?
var _anotherFunctionWithTrailingClosure: (() -> ())?
func someFunctionWithTrailingClosure(closure: #escaping () -> ()) {
print("starting someFunctionWithTrailingClosure")
_someFunctionWithTrailingClosure = closure
DispatchQueue.global().asyncAfter(deadline: .now() + 1) { [weak self] in
self?._someFunctionWithTrailingClosure!()
print("finishing someFunctionWithTrailingClosure")
}
}
func anotherFunctionWithTrailingClosure(closure: #escaping () -> ()) {
print("starting anotherFunctionWithTrailingClosure")
_anotherFunctionWithTrailingClosure = closure
DispatchQueue.global().asyncAfter(deadline: .now() + 1) { [weak self] in
self?._anotherFunctionWithTrailingClosure!()
print("finishing anotherFunctionWithTrailingClosure")
}
}
func doSomething() {
print("doSomething")
}
public func testCompletionHandlers() {
someFunctionWithTrailingClosure { [weak self] in
guard let self = self else { return }
self.anotherFunctionWithTrailingClosure { // [weak self] in
self.doSomething()
}
}
}
// go ahead and add `deinit`, so I can see when this is deallocated
deinit {
print("deinit")
}
}
func performExperiment() {
let obj = CaptureListExperiment()
obj.testCompletionHandlers()
Thread.sleep(forTimeInterval: 1.3)
}
performExperiment()
/* Output:
starting someFunctionWithTrailingClosure
starting anotherFunctionWithTrailingClosure
finishing someFunctionWithTrailingClosure
doSomething
finishing anotherFunctionWithTrailingClosure
*/
Notice that deinit is not called, since a retain cycle was created.
This could be fixed by either removing the strong reference (EX2):
public func testCompletionHandlers() {
someFunctionWithTrailingClosure { [weak self] in
//guard let self = self else { return }
self?.anotherFunctionWithTrailingClosure { // [weak self] in
self?.doSomething()
}
}
}
Or using the weak/strong/weak dance (EX3):
public func testCompletionHandlers() {
someFunctionWithTrailingClosure { [weak self] in
guard let self = self else { return }
self.anotherFunctionWithTrailingClosure { [weak self] in
self?.doSomething()
}
}
}
Updated for Swift 4.2:
public class CaptureListExperiment {
public init() {
}
func someFunctionWithTrailingClosure(closure: #escaping () -> ()) {
print("starting someFunctionWithTrailingClosure")
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
closure()
print("finishing someFunctionWithTrailingClosure")
}
}
func anotherFunctionWithTrailingClosure(closure: #escaping () -> ()) {
print("starting anotherFunctionWithTrailingClosure")
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
closure()
print("finishing anotherFunctionWithTrailingClosure")
}
}
func doSomething() {
print("doSomething")
}
public func testCompletionHandlers() {
someFunctionWithTrailingClosure { [weak self] in
guard let self = self else { return }
self.anotherFunctionWithTrailingClosure { // [weak self] in
self.doSomething()
}
}
}
// go ahead and add `deinit`, so I can see when this is deallocated
deinit {
print("deinit")
}
}
try it Playgorund:
func performExperiment() {
let obj = CaptureListExperiment()
obj.testCompletionHandlers()
Thread.sleep(forTimeInterval: 1.3)
}
performExperiment()