Swift: does capturing a function parameter, within a closure, hold it strongly? - ios

Capturing a function parameter within a closure
func someFunction(tableView: UITableView) -> (() -> ()) {
return { [weak self] in
self?.someOtherFunction() {
tableView.performTask()
}
}
}
If so, what is the syntax for ensuring the tableView parameter is weak, in the above example?

Closure capture parameters strongly by default. In most common cases in closure you accessing to properties declared in self, without capturing other references, so making self weak is enough. In your case you need expand closure capture list and include tableView to it:
func someFunction(tableView: UITableView) -> (() -> ()) {
return { [weak self, weak tableView] in
self?.someOtherFunction() {
tableView?.performTask()
}
}
}
You may read more about capture lists in ARC documentation:
You resolve a strong reference cycle between a closure and a class
instance by defining a capture list as part of the closure’s
definition. A capture list defines the rules to use when capturing
one or more reference types within the closure’s body. As with strong reference cycles between two class instances, you declare each
captured reference to be a weak or unowned reference rather than a
strong reference.

Related

Error: Assigning non-escaping parameter 'publicationQuery' to an #escaping closure

I have a view controller like this:
class PublicationListViewController: UIViewController {
var publicationQuery: (() -> [Publication])!
func initWith(title: String, publicationQuery: () -> [Publication]) {
self.title = title
self.publicationQuery = publicationQuery
}
}
Why am I getting a "Assigning non-escaping parameter 'publicationQuery' to an #escaping closure" error?
Escaping Closures
Because by storing the publicationQuery into a property you are allowing it to "escape" from the initializer (it lives even after the initiliazer finished its execution, thus is a potential cause of retain cycle). To be able to do that you have to explicitly mark it as escaping using #escaping annotation:
class PublicationListViewController: UIViewController {
var publicationQuery: (() -> [String])!
// notice that now publicationQuery uses #escaping annotation
func initWith(title: String, publicationQuery: #escaping () -> [String]) {
self.title = title
self.publicationQuery = publicationQuery
}
}
Read more about escaping in Escaping Closures section of the Closures documentation.
Preventing Retain Cycle
When using escaping closures, you have to be careful not to create a retain cycle. Easiest way is to use the capture list when creating escaping closure, and in that capture list you explicitly capture self as a weak reference:
// use [weak self] capture list to make sure that you don't create another strong reference to self
pubController.initWith(title: "Title") { [weak self] () -> [String] in
// use guard to safely unwrap the self
guard let `self` = self else { return }
// here self will be non-optional value that you can directly use
}

Optimizing capture lists

Is there such a thing? Is there any difference between the two below? Is one more "correct" than the other?
All objects are properties of self (let's say a view controller) and have the same lifetime as self. We can introduce an object with a shorter lifetime than self, which would be weak, but the same question applies.
objectOne.doSomething { [unowned self] in
self.objectTwo.finish()
self.tableView.reloadData()
// self.someDelegate?.didFinishSomething()
}
vs
objectOne.doSomething {
[unowned objectTwo = self.objectTwo,
unowned tableView = self.tableView
// weak someDelegate = self.delegate
] in
objectTwo.finish()
tableView.reloadData()
// someDelegate?.didFinishSomething()
}
Apple has this example in their docs:
lazy var someClosure: () -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
delegate?.doSomething()
}
In this case, delegate can have a shorter lifetime than self, but why not use it like this?
lazy var someClosure: () -> String = {
[unowned self] in
// closure body goes here
self.delegate?.doSomething()
}
Yes, there is an important difference. In the case of the Apple docs, the code alternative you presented:
lazy var someClosure: () -> String = {
[unowned self] in
// closure body goes here
self.delegate?.doSomething()
}
will look up the current delegate on self when the closure runs.
In the Apple example version:
lazy var someClosure: () -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
delegate?.doSomething()
}
the weak delegate var in the capture list is copying the delegate pointer on self that exists at the time of closure declaration, not execution. So if the value of self.delegate changes after the closure is declared and is different at the time the closure runs, the Apple version of the closure will have a nil delegate (assumedly since the reference to the old delegate was weak) and do nothing.
So as a general rule, copying values or references in capture lists ([someIdentifier = someProperty]) is how to use the values or references as they exist at the moment the closure is defined. Whereas declaring weak or unowned self in the capture list ([weak self]) and then accessing properties on that weak reference ({ self?.someProperty }) will get the values of the properties as they exist when the closure is executed.
One of the problems that [unowned objectOne = self.objectOne] might cause is with lazy var UIViews and racing conditions: if you aren't careful and the lazy init gets called from different threads, two instances might end up being created. Furthermore, if your superview.addSubview(objectOne) call is in the lazy init, both instances will be added to the superview, and objectOne will point to one of the two instances.

ARC in Swift how to resolve strong reference cycle when assign property as function

Flowing code, I did try to create an object assign object property to a functions. And after init object I did try assign it to nil. But object did not release (because deinit never called).
I think problem is strong reference cycle between property and owner object. If really has strong reference cycle here, how to resolve this problem when assign property directly with a function?
class MyClass {
var aProperty: (() -> ())?
init() {
// problem when assign property as a method
self.aProperty = aMethod
}
func aMethod() {
print("method!!!")
}
deinit {
print("MyClass is being deinitialized")
}
}
var instance: MyClass? = MyClass()
instance?.aProperty?()
instance = nil
You resolve a strong reference cycle between a closure and a class instance by defining a capture list as part of the closure’s definition. A capture list defines the rules to use when capturing one or more reference types within the closure’s body. As with strong reference cycles between two class instances, you declare each captured reference to be a weak or unowned reference rather than a strong reference. The appropriate choice of weak or unowned depends on the relationships between the different parts of your code.
lazy var someClosure: Void -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
}
from
Strong Reference Cycles for Closures
In your case you should apply capture list when assigning a method to the property like this
init() {
self.aProperty = { [unowned self] in self.aMethod() }
}
You can still use a capture list to prevent the cycle. Just wrap the method call in a closure as shown in the code below.
class MyClass {
var aProperty: (() -> ())?
init() {
// use a capture list to prevent a reference cycle
self.aProperty = { [unowned self] in self.aMethod() }
}
func aMethod() {
print("method!!!")
}
deinit {
print("MyClass is being deinitialized")
}
}
var instance: MyClass? = MyClass()
instance?.aProperty?()
instance = nil
This eliminates the strong reference cycle in my testing.

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.

Resources