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

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
}

Related

Implicit self in #escaping Closures when Reference Cycles are Unlikely to Occur Swift 5.3

With SE-0269 we won’t need to use explicit anymore in the below case for reference type.
class Test {
var x = 0
func execute(_ work: #escaping () -> Void) {
work()
}
func method() {
execute { [self] in
x += 1
}
}
}
Will this handle [weak self] and [unowned self] or we should explicitly use in the case of weak and unowned for this proposal.
You still need to manually specify weak and unowned captures of self. The only change SE-0269 results in is that you don't need to explicitly write out self. when accessing instance properties/methods when acknowledging that you capture self strongly by using [self].
In case of [weak self] you still need to explicitly write self. in the closure, but when using [unowned self], you can omit self. just as when using [self].
execute { [weak self] in
x += 1 // Error: Reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit
}
execute { [weak self] in
self?.x += 1 // need to manually specify `self?.`
}
execute { [unowned self] in
x += 1 // compiles fine
}

Passing self and returning it in a closure without retain cycle

I'm tired of using the [weak self] capture in closures, so I would like to pass self and return that in the closure like this:
alertManager.askToConfirm(from: self) { vc, confirmed in
if confirmed {
vc.model.confirm()
} else {
vc.model.reject()
}
}
inside AlertManager my code would be like this:
func askToConfirm<T>(from vc: T, completion: #escaping (T) -> ()) {
let invitation = pageItemFactory.createConfirmationPageItem() { [weak self] accepted in
self?.dismissAlert()
completion(vc, accepted)
}
present(invitation)
}
Will this create a retain cycle?
No, from what I can see, this will not result in a retain cycle.
For example, this will result in a retain cycle. When myFunction executes, the Foo instance will hold a strong reference to the completion block. In turn, the completion block holds a strong reference to the Foo instance. This will a retain cycle, and in this case you need to add a capture list.
class Foo<T> {
var completion: (T) -> ()
func myFunction(_ vc: T, completion: #escaping (T) -> ()) {
self.completion = completion // This will create a retain cycle
completion(vc)
}
func doSomething() {
myFunction(self) { vc in
print(vc)
}
}
}

Why there is no `self` in the closure in the function `makeConstraints` by SnapKit?

starLabel.snp.makeConstraints { make in
make.left.equalTo(starImageView.snp.right).offset(5)
make.centerY.equalToSuperview()
}
The starImageView and starLabel are the properties of current view controller. But, why can I ignore the self(self.starImageView) in the closure which is the param in makeConstraints?
And in my closure, I must write the self explicitly, or the compiler will report a error:
Reference to property 'starImageView' in closure requires explicit 'self.' to make capture semantics explicit
Insert 'self.'
public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
ConstraintMaker.makeConstraints(item: self.view, closure: closure)
}
Because the closure is not #escaping,so it means the closure will just run in the function. When the function over the closure will be released.
Only the function can hold the closure.
It's because equalTo looks like this:
public func equalTo(_ other: ConstraintRelatableTarget, _ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
return self.relatedTo(other, relation: .equal, file: file, line: line)
}
And ConstraintRelatableTarget is a protocol that leads to different types as Int, Float etc. You also have a reference to a ConstraintItem which is this case is the view you refer to, and this is how it looks:
internal weak var target: AnyObject?
internal let attributes: ConstraintAttributes
internal init(target: AnyObject?, attributes: ConstraintAttributes) {
self.target = target
self.attributes = attributes
}
internal var layoutConstraintItem: LayoutConstraintItem? {
return self.target as? LayoutConstraintItem
}
As it appears, both Any? and AnyObject? (I dont think it has to be optional) does not need self to be reached. Hence, anything you put in to the equalTo function, is seen by snapKit as an AnyObject? and therefor don't need a self reference.

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

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.

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