[英]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. 在我的TextViewTableViewCell
,我有一个变量来跟踪块和一个configure方法,其中传入和分配块。
Here is my TextViewTableViewCell
class: 这是我的TextViewTableViewCell
类:
//
// 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. 当我在cellForRowAtIndexPath
方法中使用configure方法时,如何在我传入的块中正确使用弱自我。
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]
: 更新 :我使用[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. 当我做[unowned self]
而不是[weak self]
并取出if
语句时,应用程序崩溃了。 Any ideas on how this should work with [unowned self]
? 关于如何与[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 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: 注意:我使用了术语closure而不是block ,这是更新的Swift术语:
Difference between block (Objective C) and closure (Swift) in ios ios中块(目标C)和闭包(Swift)之间的区别
Put [unowned self]
before (text: String)...
in your closure. 将[unowned self]
放在(text: String)...
闭包(text: String)...
之前(text: String)...
This is called a capture list and places ownership instructions on symbols captured in the closure. 这称为捕获列表 ,并将所有权指令放在闭包中捕获的符号上。
**EDITED for Swift 4.2: **为Swift 4.2编辑:
As @Koen commented, swift 4.2 allows: 正如@Koen评论的那样,swift 4.2允许:
guard let self = self else {
return // Could not get a strong reference for self :`(
}
// Now self is a strong reference
self.doSomething()
PS: Since I am having some up-votes, I would like to recommend the reading about escaping closures . PS:由于我有一些上涨票,我想推荐关于逃避封闭的阅读。
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. 编辑:正如@ tim-vermeulen评论的那样,Chris Lattner在2016年1月22日星期五19:51:29 CST表示,这个技巧不应该用于自我,所以请不要使用它。 Check the non escaping closures info and the capture list answer from @gbk.** 检查@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 对于那些在捕获列表中使用[弱自我]的人,请注意self可以是nil,所以我要做的第一件事就是用一个保护声明来检查
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.如果你想知道引号是什么周围的 self
是一个专业技巧,在封闭中使用self而无需将名称更改为this , weakSelf或其他。
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!). 捕获列表中的每个项都是弱或无主关键字与对类实例(如self)的引用或使用某个值初始化的变量(如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: 如果闭包没有指定参数列表或返回类型,因为它们可以从上下文中推断出来,请将捕获列表放在闭包的最开头,然后是in关键字:
lazy var someClosure: Void -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
}
EDIT: Reference to an updated solution by LightMan 编辑:参考LightMan的更新解决方案
See LightMan's solution . 请参阅LightMan的解决方案 。 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: 如果没有参数,或者在闭包中将其称为$0
,则可以完全省略参数:
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
: 如果你将闭包传递给函数并且参数不是@escaping
,那么你不需要weak self
:
[1,2,3,4,5].forEach { self.someCall($0) }
Swift 4.2 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 https://github.com/apple/swift-evolution/blob/master/proposals/0079-upgrade-self-from-weak-to-strong.md
_ = { [weak self] value in
guard let self = self else { return }
print(self) //👈 will never be nil
}()
You can use [weak self] or [unowned self] in the capture list prior to your parameters of the block. 您可以在块的参数之前在捕获列表中使用[weak self]或[unowned self]。 The capture list is optional syntax. 捕获列表是可选语法。
[unowned self]
works good here because the cell will never be nil. [unowned self]
在这里运作良好,因为细胞永远不会是零。 Otherwise you can use [weak self]
否则你可以使用[weak self]
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. 创建一个prepareForReuse并尝试清除其中的onTextViewEditClosure块。
func prepareForResuse() {
onTextViewEditClosure = nil
textView.delegate = nil
}
See if that prevents the crash. 看看是否可以防止崩溃。 (It's just a guess). (这只是猜测)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.