ios 如何正确处理带有参数的 Swift 块中的 Weak Self
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24468336/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Correctly handle Weak Self in Swift Blocks with Arguments
提问by NatashaTheRobot
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:
在 my 中TextViewTableViewCell
,我有一个变量来跟踪一个块和一个配置方法,其中块被传入和分配。
这是我的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.
Here is what I have without the weak self:
当我在我的cellForRowAtIndexPath
方法中使用 configure 方法时,我如何在我传入的块中正确使用弱自我。
这是我没有弱自我的情况:
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. Any ideas on how this should work with [unowned self]
?
当我执行[unowned self]
而不是[weak self]
取出if
语句时,应用程序崩溃。关于这应该如何工作的任何想法[unowned self]
?
回答by TenaciousJay
If selfcould be nil in the closure use [weak self].
如果self在闭包中可以为零,请使用[weak self]。
If selfwill never be nil in the closure use [unowned self].
如果self在闭包中永远不会为零,请使用[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.
如果当你使用[unowned self]时它崩溃了,我猜在那个闭包的某个时刻 self 为零,这就是为什么你不得不使用[weak self]代替。
I really liked the whole section from the manual on using strong, weak, and unownedin closures:
我真的很喜欢手册中关于在闭包中使用strong、weak和unowned的整个部分:
Note: I used the term closureinstead of blockwhich is the newer Swift term:
注意:我使用了术语闭包而不是块,这是较新的 Swift 术语:
Difference between block (Objective C) and closure (Swift) in ios
回答by ikuramedia
Put [unowned self]
before (text: String)...
in your closure. This is called a capture listand places ownership instructions on symbols captured in the closure.
放在你的闭包[unowned self]
之前(text: String)...
。这称为捕获列表,并将所有权说明放置在闭包中捕获的符号上。
回答by LightMan
**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()
P.S.: 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. Check the non escaping closures info and the capture list answer from @gbk.**
编辑:正如@tim-vermeulen 所评论的那样,Chris Lattner 在 2016 年 1 月 22 日星期五 19:51:29 CST 上说,这个技巧不应该用于自己,所以请不要使用它。检查来自@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, weakSelfor whatever.
对于那些在捕获列表中使用 [weak self] 的人,请注意 self 可能为零,所以我要做的第一件事是使用保护语句进行检查
guard let `self` = self else {
return
}
self.doSomething()
如果你想知道引号周围self
是什么是在闭包中使用 self 而不需要将名称更改为this、weakSelf或其他什么的专业技巧。
回答by Ferran Maylinch
EDIT: Reference to an updated solution by LightMan
编辑:参考 LightMan 更新的解决方案
See LightMan's solution. Until now I was using:
请参阅LightMan 的解决方案。到目前为止,我一直在使用:
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([1,2,3,4,5].forEach { self.someCall(lazy var someClosure: (Int, String) -> String = {
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
// closure body goes here
}
) }
) // 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
:
lazy var someClosure: Void -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
}
回答by gbk
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:
定义捕获列表
捕获列表中的每一项都是weak 或unowned 关键字与对类实例的引用(例如self)或用某个值初始化的变量(例如delegate = self.delegate!)的配对。这些配对写在一对方括号内,用逗号分隔。
将捕获列表放在闭包的参数列表和返回类型(如果提供)之前:
_ = { [weak self] value in
guard let self = self else { return }
print(self) // will never be nil
}()
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 关键字:
let closure = { [weak self] (_ parameter:Int) in
guard let self = self else { return }
self.method(parameter)
}
回答by eonist
As of swift 4.2 we can do:
从 swift 4.2 开始,我们可以执行以下操作:
func prepareForResuse() {
onTextViewEditClosure = nil
textView.delegate = nil
}
回答by Alan McCosh
Swift 4.2
斯威夫特 4.2
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
}
}
}
回答by Rufus
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.
您可以在块的参数之前在捕获列表中使用 [weak self] 或 [unowned self]。捕获列表是可选语法。
[unowned self]
works good here because the cell will never be nil. Otherwise you can use [weak self]
[unowned self]
在这里效果很好,因为单元格永远不会为零。否则你可以使用[weak self]
回答by Michael Gray
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 块。
##代码##See if that prevents the crash. (It's just a guess).
看看这是否可以防止崩溃。(这只是一个猜测)。
回答by yoAlex5
Closure and strong reference cycles[About]
闭包和强引用循环[关于]
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
which. By the way you have to explicitly use self
inside escaping closure
.
如您所知,Swift 的闭包可以捕获实例。这意味着您可以self
在闭包内使用。尤其是escaping closure
[About]可以创建strong reference cycle
which。顺便说一句,您必须明确使用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.
Swift 闭包具有Capture List
允许您避免这种情况并打破引用循环的功能,因为没有对捕获的实例的强引用。捕获列表元素是一对weak
/unowned
和对类或变量的引用。
For example
例如
##代码##weak
- more preferable, use it when it is possibleunowned
- use it when you are sure that lifetime of instance owner is bigger than closure
weak
- 更可取的是,在可能的情况下使用它unowned
- 当您确定实例所有者的生命周期大于闭包时使用它