ARC Retain Cycles, Grand Central Dispatch and Closures - ios

I understand that if you assign a closure to a property such as:
var someClosure : () -> Void?
let someConstant : Int = 5
And call that closure from its class' init with a reference to self:
someClosure = { print(self.someConstant) }
Then this will result in a retain cycle, so I should use weak to avoid it.
But I couldn't understand the following code which is from a raywenderlich.com tutorial:
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
guard let self = self else {
return
}
self.someFunction()
}
Why a retain cycle exists here - since we didn't create a reference from view to closure (i.e., saving closure as a property) but only from closure to self; shouldn't it be retain cycle-free?

You are right and Ray is wrong:
Grand Central Dispatch closures don't cause retain cycles.
You can delete
[weak self] in
guard let self = self else {
return
}
Please see also https://digitalleaves.com/blog/2015/05/demystifying-retain-cycles-in-arc/

Related

What is the meaning of following swift code?

Can anyone tell me why we use guard let self = self ??
I have seen this code while reading about GCD, I couldn't figure out what that particular line does.
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
guard let self = self else {
return
}
// ...
}
First you are creating a block that will be executed asynchronously
DispatchQueue.global(qos: .userInitiated).async
Then inside the block the code checks if self, the object that is calling this function, is still allocated
guard let self = self else {
return
}
We need to check this because self is declared as weak inside the block to avoid a retain cycle (Swift closures causing strong retain cycle with self) and can be deallocated before the block is executed. That line of code checks if self is != nil, and assign it to self, otherwise it returns.
self is declared weak in this block, so it has an Optional type. E.g. if the name of your class is MyViewController then the type of self in that block is MyViewController?. The reason for the use of weak is to avoid retain cycles. The block should only execute if self is still alive. So one solution would be:
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
guard let strongSelf = self else {
return
}
strongSelf.makeFoo()
strongSelf.continueWithBar()
}
but there is no need to call it strongSelf. You can call it self too. The self variable after the guard block is actually a different variable than self, it just has the same name.
So the meaning is:
Execute this block only if self is still alive. (Otherwise, do nothing.)
The code inside async {} will b executed asynchronously. The completion function ({ [weak self] ... }) contains a (default strong) reference to the object calling the async function.
Since it is asynchronous you don't have a way to know a) when the callback will be executed b) if it will be executed. Meaning that the strong reference to self could cause a memory leak.
That is why one uses [weak self] to pass a weak reference. Since the call is async, it can be that, when the callback is finally executed, the ARC has already collected the reference to self and thus self would be nil.
It is then good to check if self still exists before executing the code in the callback.
A thread is being created and added to global queue and has QOS(Quality of service or you can say priority of that thread) user initiated(medium priority) after that you execute set of instructions async

Should I weakify "local" variables used in a block?

This is not another question about [weak self]. This is about use of variables not contained by self, but rather by the wrapping function.
func someFunction(){
someOtherFunction(completionBlock:{ [weak self] in
self?.doStuff()
})
}
As far as I understand, I need the [weak self] in order to prevent a retain cycle.
But what if I need to use a variable from the wrapping function, like this:
func someFunction(){
let someVariable = MyObject()
someOtherFunction(completionBlock:{ [weak self] in
self?.doStuff(with: someVariable)
})
}
This works, which makes me wonder.. How, and how long is someVariable held in memory? Can it create its own tiny retain cycle where my completion block strongly references the local someVariable? How will they be released? Should I add [weak self, weak someVariable] in the block? But then, won't someVariable be released immediately after I call someOtherFunction, because it's the end of this function - and the end of someVariable's lifetime..?
I'm having trouble completely understanding references, and can't see how my completionBlock and someVariable will ever be released.. Are blocks even released?
Any variable referenced inside a closure will be strongly retained by that closure. You can adjust that by including a closure capture list (e.g. [weak self]), which allows you to specify the particular memory management pattern of references captured in the closure.
func someFunction(){
let someVariable = MyObject()
someOtherFunction(completionBlock:{ [weak self] in
self?.doStuff(with: someVariable)
})
}
Here, someVariable is retained by the closure, as you have stated. In this case, it has to be, because nobody else cares about it. As you've mentioned in comments, if you used a capture list of [weak someVariable] then it would always be nil when the completion block executed, as it has gone out of scope in it's original function.
A "tiny retain cycle" isn't being created. A retain cycle has to be a cycle - that is, A holds a strong reference to B, which holds a strong reference to A. someVariable doesn't have references to anything.
Once someOtherFunction has finished with the reference to the completion closure, everything goes away. The closure is just another variable as far as someOtherFunction is concerned, and it will survive as long as it is in scope.
Should I weakify “local” variables used in a block? - no, as they will then be nil by the time the block comes to use them.
I would like to mention not so clear option, what is very usual place to create retain cycle and where you should be aware of weaken variables.
Lets consider this situation:
func someFunction() {
let object = Something()
object.handler = { [weak self] in
self?.doStuff(with: object)
}
}
Now there is retain cycle, and object cannot be deallocated until somebody manually unset the handler. Because now object strongify itself in the captured block.
So better solution is:
func someFunction() {
let object = Something()
object.handler = { [weak self, unowned object] in
self?.doStuff(with: object)
}
}
And good practice is pass the object as argument in handler
func someFunction() {
let object = Something()
object.handler = { [weak self] (object) in
self?.doStuff(with: object)
}
}
So signature of this should look like:
class Something {
var handler:((Something) -> Void)?
deinit {
print("retain cycle is not here")
}
}

Correct placement of capture list in nested closures in swift

Where do I define captured references for nested closures in Swift?
Take this code as an example:
import Foundation
class ExampleDataSource {
var content: Any?
func loadContent() {
ContentLoader.loadContentFromSource() { [weak self] loadedContent in
// completion handler called on background thread
dispatch_async(dispatch_get_main_queue()) { [weak self] in
self?.content = loadedContent
}
}
}
}
class ContentLoader {
class func loadContentFromSource(completion: (loadedContent: Any?) -> Void) {
/*
Load content from web asynchronously,
and call completion handler on background thread.
*/
}
}
In this example, [weak self] is used in both trailing closures, however the compiler is perfectly happy if I omit [weak self] from either one of the trailing closures.
So that leaves me 3 options for defining my capture list:
define captures on every nested closure leading up to the reference
define captures on the first closure only.
define captures on only the most nested closure that actually uses the reference.
My question is:
If I know that my ExampleDataSource could be nil at some point, what is the best option to go with?
It is important to note that GCD dispatch_async will NOT cause a retain cycle. In other words, when the block has finished executing, GCD will not retain any references made within the block.
The same is not true for strong references between classes, or strong references within a closure assigned to a property of an instance. Apple Documentation
That being said, in this example, the correct answer is option 2, to define captures on the first closure only.
For testing purposes I modified the code slightly:
class ExampleDataSource {
init() {
print("init()")
}
deinit {
print("deinit")
}
var content: Any?
func loadContent() {
print("loadContent()")
ContentLoader.loadContentFromSource() { [weak self] loadedContent in
dispatch_async(dispatch_get_main_queue()) {
print("loadedContent")
self?.content = loadedContent
}
}
}
}
class ContentLoader {
class func loadContentFromSource(completion: (loadedContent: Any?) -> Void) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)) {
sleep(5) // thread will hang for 5 seconds
completion(loadedContent: "some data")
}
}
}
First I create, var myDataSource: ExampleDataSource? = ExampleDataSource().
Then I run myDataSource.loadContent().
Before the completion handler gets a chance to run, I set myDataSource = nil, removing all references to it.
The debug console indicates that a reference to self was not retained:
init()
loadContent()
deinit
loadedContent
Looks like we found our answer! But just for completion's sake, let's test the alternatives...
If [weak self] is instead captured on only the inner most trailing closure, GCD will retain ExampleDataSource until the block has finished executing, which explains why the debug would instead look like this:
init()
loadContent()
loadedContent
deinit
The same thing will happen if no capture list is included and we never optionally unwrapped self, although the compiler, does try to warn you!
While it isn't technically incorrect to include [weak self] captures in all trailing closures, it does detract from the readability of code and doesn't feel very 'Swift-like'.

How to set a weak reference to a closure/function in Swift?

In HMSegmentedControl, I'd like to set the segmentedControl.indexChangeBlock to an instance method to handle the action.
The official example is: https://github.com/HeshamMegid/HMSegmentedControl/blob/master/HMSegmentedControlExample/HMSegmentedControlExample/ViewController.m (Line 63 ~ 68), but that's Objective-C.
In Swift, functions are first class citizens. So I wanna set an instance method to this block property.
But my code would lead to a circular reference, it seems that I should define a weak reference:
class ExampleVC: UIViewController {
var segmentedControlIndex: Int = 0
override func viewDidLoad() {
let segmentedControl3 = HMSegmentedControl(sectionImages: ... , sectionSelectedImages: ... )
segmentedControl3.frame = ...
segmentedControl3.indexChangeBlock = someInstanceMethod
}
func someInstanceMethod(index: Int) {
segmentedControlIndex = index
}
}
However, I cannot define a weak reference to a non-class type. What can I do? Is it legal to do this?
[unowned self] is dangerous. What this does is to tell the runtime 'Assume self has not been released, don't worry about checking.' If self does get released in the meantime, your application will SEGFAULT.
In this case, { [weak self] in self?.someInstanceMethod($0) } will break the reference cycle, and turns into a no-op if self is released.
[weak self] is always safe, while [unowned self] can introduce app crashes if you modify other areas of your code (like view hierarchy, for example)...
Instead of defining weak reference to the closure, you should use "Capture List" in the closure.
segmentedControl3.indexChangeBlock = { [unowned self] in self.someInstanceMethod($0) }
As far as I know, this is the only way to avoid strong reference cycles.

How to Correctly handle Weak Self in Swift Blocks with Arguments

In my TextViewTableViewCell, I have a variable to keep track of a block and a configure method where the block is passed in and assigned.
Here is my TextViewTableViewCell class:
//
// TextViewTableViewCell.swift
//
import UIKit
class TextViewTableViewCell: UITableViewCell, UITextViewDelegate {
#IBOutlet var textView : UITextView
var onTextViewEditClosure : ((text : String) -> Void)?
func configure(#text: String?, onTextEdit : ((text : String) -> Void)) {
onTextViewEditClosure = onTextEdit
textView.delegate = self
textView.text = text
}
// #pragma mark - Text View Delegate
func textViewDidEndEditing(textView: UITextView!) {
if onTextViewEditClosure {
onTextViewEditClosure!(text: textView.text)
}
}
}
When I use the configure method in my cellForRowAtIndexPath method, how do I properly use weak self in the block that I pass in.
Here is what I have without the weak self:
let myCell = tableView.dequeueReusableCellWithIdentifier(textViewCellIdenfitier) as TextViewTableViewCell
myCell.configure(text: body, onTextEdit: {(text: String) in
// THIS SELF NEEDS TO BE WEAK
self.body = text
})
cell = bodyCell
UPDATE: I got the following to work using [weak self]:
let myCell = tableView.dequeueReusableCellWithIdentifier(textViewCellIdenfitier) as TextViewTableViewCell
myCell.configure(text: body, onTextEdit: {[weak self] (text: String) in
if let strongSelf = self {
strongSelf.body = text
}
})
cell = myCell
When I do [unowned self] instead of [weak self] and take out the if statement, the app crashes. Any ideas on how this should work with [unowned self]?
If self could be nil in the closure use [weak self].
If self will never be nil in the closure use [unowned self].
If it's crashing when you use [unowned self] I would guess that self is nil at some point in that closure, which is why you had to go with [weak self] instead.
I really liked the whole section from the manual on using strong, weak, and unowned in closures:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html
Note: I used the term closure instead of block which is the newer Swift term:
Difference between block (Objective C) and closure (Swift) in ios
**EDITED for Swift 4.2:
As #Koen commented, swift 4.2 allows:
guard let self = self else {
return // Could not get a strong reference for self :`(
}
// Now self is a strong reference
self.doSomething()
P.S.: Since I am having some up-votes, I would like to recommend the reading about escaping closures.
EDITED: As #tim-vermeulen has commented, Chris Lattner said on Fri Jan 22 19:51:29 CST 2016, this trick should not be used on self, so please don't use it. Check the non escaping closures info and the capture list answer from #gbk.**
For those who use [weak self] in capture list, note that self could be nil, so the first thing I do is check that with a guard statement
guard let `self` = self else {
return
}
self.doSomething()
If you are wondering what the quote marks are around self is a pro trick to use self inside the closure without needing to change the name to this, weakSelf or whatever.
EDIT: Reference to an updated solution by LightMan
See LightMan's solution. Until now I was using:
input.action = { [weak self] value in
guard let this = self else { return }
this.someCall(value) // 'this' isn't nil
}
Or:
input.action = { [weak self] value in
self?.someCall(value) // call is done if self isn't nil
}
Usually you don't need to specify the parameter type if it's inferred.
You can omit the parameter altogether if there is none or if you refer to it as $0 in the closure:
input.action = { [weak self] in
self?.someCall($0) // call is done if self isn't nil
}
Just for completeness; if you're passing the closure to a function and the parameter is not #escaping, you don't need a weak self:
[1,2,3,4,5].forEach { self.someCall($0) }
Put [unowned self] before (text: String)... in your closure. This is called a capture list and places ownership instructions on symbols captured in the closure.
Use Capture list
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: Void -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
}
additional explanations
As of swift 4.2 🔸 we can do:
_ = { [weak self] value in
guard let self = self else { return }
print(self) //👈 will never be nil
}()
Swift 4.2
let closure = { [weak self] (_ parameter:Int) in
guard let self = self else { return }
self.method(parameter)
}
https://github.com/apple/swift-evolution/blob/master/proposals/0079-upgrade-self-from-weak-to-strong.md
You can use [weak self] or [unowned self] in the capture list prior to your parameters of the block. The capture list is optional syntax.
[unowned self] works good here because the cell will never be nil. Otherwise you can use [weak self]
From Swift 5.3, you do not have to unwrap self in closure if you pass [self] before in in closure.
Refer someFunctionWithEscapingClosure { [self] in x = 100 } in this swift doc
If you are crashing than you probably need [weak self]
My guess is that the block you are creating is somehow still wired up.
Create a prepareForReuse and try clearing the onTextViewEditClosure block inside that.
func prepareForResuse() {
onTextViewEditClosure = nil
textView.delegate = nil
}
See if that prevents the crash. (It's just a guess).
[Closure and strong reference cycles]
As you know Swift's closure can capture the instance. It means that you are able to use self inside a closure. Especially escaping closure[About] can create a strong reference cycle[About]. By the way you have to explicitly use self inside escaping closure.
Swift closure has Capture List feature which allows you to avoid such situation and break a reference cycle because do not have a strong reference to captured instance. Capture List element is a pair of weak/unowned and a reference to class or variable.
For example
class A {
private var completionHandler: (() -> Void)!
private var completionHandler2: ((String) -> Bool)!
func nonescapingClosure(completionHandler: () -> Void) {
print("Hello World")
}
func escapingClosure(completionHandler: #escaping () -> Void) {
self.completionHandler = completionHandler
}
func escapingClosureWithPArameter(completionHandler: #escaping (String) -> Bool) {
self.completionHandler2 = completionHandler
}
}
class B {
var variable = "Var"
func foo() {
let a = A()
//nonescapingClosure
a.nonescapingClosure {
variable = "nonescapingClosure"
}
//escapingClosure
//strong reference cycle
a.escapingClosure {
self.variable = "escapingClosure"
}
//Capture List - [weak self]
a.escapingClosure {[weak self] in
self?.variable = "escapingClosure"
}
//Capture List - [unowned self]
a.escapingClosure {[unowned self] in
self.variable = "escapingClosure"
}
//escapingClosureWithPArameter
a.escapingClosureWithPArameter { [weak self] (str) -> Bool in
self?.variable = "escapingClosureWithPArameter"
return true
}
}
}
weak - more preferable, use it when it is possible
unowned - use it when you are sure that lifetime of instance owner is bigger than closure
[weak vs unowned]

Resources