Ios 如何正确处理带参数的Swift块中的弱Self
在我的Ios 如何正确处理带参数的Swift块中的弱Self,ios,swift,retain-cycle,Ios,Swift,Retain Cycle,在我的TextViewTableViewCell中,我有一个用于跟踪块的变量和一个用于传递和分配块的配置方法。 这是我的TextViewTableViewCell类: // // TextViewTableViewCell.swift // import UIKit class TextViewTableViewCell: UITableViewCell, UITextViewDelegate { @IBOutlet var textView : UITextView
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)
}
}
}
当我在我的cellforrowatinexpath
方法中使用configure方法时,如何在传入的块中正确使用弱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
更新:我使用[弱自我]
实现了以下功能:
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
当我执行
[无主自我]
而不是[弱自我]
并取出if
语句时,应用程序崩溃。关于如何使用[unowned self]
的任何想法?将[unowned self]
放在(文本:字符串)…
之前。这称为捕获列表,并在闭包中捕获的符号上放置所有权说明。在块参数之前,您可以在捕获列表中使用[weak self]或[unowned self]。捕获列表是可选语法
[unowned self]
在这里运行良好,因为单元格永远不会为零。否则,如果在闭包中self可能为零,则可以使用[弱self]
使用[弱self]
如果self在闭包中永远不会为零,请使用[无主self]
如果当你使用[无主自我]时它崩溃了,我猜在闭包的某个点上,自我是零,这就是为什么你必须使用[弱自我]
我非常喜欢手册中关于在闭包中使用strong、弱和无主的整个部分:
注意:我使用了术语closure而不是block,后者是较新的Swift术语:
如果你的崩溃超出了你可能需要的程度[虚弱的自我] 我的猜测是,你正在创建的块不知何故仍然连接在一起 创建prepareForReuse并尝试清除其中的onTextViewEditClosure块
func prepareForResuse() {
onTextViewEditClosure = nil
textView.delegate = nil
}
看看这是否能防止撞车。(这只是猜测)。使用
定义捕获列表
捕获列表中的每一项都是弱项或无主项的配对
引用类实例(如self)或
用某个值初始化的变量(如委托=
自我授权!)。这些配对写在一对正方形内
大括号,用逗号分隔
将捕获列表放在闭包的参数列表之前并返回
如果提供,请键入:
如果闭包没有指定参数列表或返回类型,因为
它们可以从
上下文中,将捕获列表放在闭包的最开始处,
后跟in关键字:
**为Swift 4.2编辑: 正如@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()
附言:由于我有一些赞成票,我想推荐阅读关于
编辑:正如@tim vermeulen所评论的那样,Chris Lattner在2016年1月22日星期五19:51:29 CST上说,这个技巧不应该在自己身上使用,所以请不要使用它。检查@gbk中的非转义闭包信息和捕获列表答案**
对于那些在捕获列表中使用[weak self]的人,请注意self可能为零,所以我要做的第一件事是用守卫声明检查它
guard let `self` = self else {
return
}
self.doSomething()
如果你想知道self的引号是什么,那么在闭包中使用self是一个专业技巧,而不需要将名称更改为this、weakSelf或其他什么
编辑:参考LightMan更新的解决方案 看。到目前为止,我一直在使用:
input.action = { [weak self] value in
guard let this = self else { return }
this.someCall(value) // 'this' isn't nil
}
或:
通常,如果是推断的,则不需要指定参数类型
如果没有参数,或者在闭包中将其称为$0
,则可以完全忽略该参数:
input.action = { [weak self] in
self?.someCall($0) // call is done if self isn't nil
}
只是为了完整;如果将闭包传递给函数,且参数不是@escaping
,则不需要弱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)
}
正如您所知,Swift的闭包可以捕获实例。这意味着您可以在闭包内使用self
。尤其是转义闭包
可以创建一个强引用循环
。顺便说一下,您必须在转义闭包中显式使用self
Swift closure具有捕获列表
功能,该功能允许您避免这种情况,并打破引用周期,因为没有对捕获实例的强引用。捕获列表元素是一对弱
/无主
和对类或变量的引用
比如说
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
}
}
}
-更可取的做法是,在可能时使用它弱
-当您确定实例所有者的生存期大于closure时使用它unowned
从
Swift 5.3
开始,如果在中的之前通过了[self],则不必在闭包中打开self
请参阅中的
somefunction with escapingclosure{[self]in x=100}
in您能选择下面的答案作为正确答案吗?还要注意的是,在无主状态下,你不需要在闭包中强化自我。在这里,无主比弱好,因为你的手机和视图控制器的生命周期是链接的。我意识到,[无主自我]如果是更好的选择,但我的应用程序在使用它时崩溃。希望看到一个代码示例使用它来结束答案。从文档中可以看出:“像弱引用一样,无主引用不会对它引用的实例保持很强的控制力。但是,与弱引用不同,无主引用总是假定有一个值。”如果你的应用程序崩溃,很可能是因为无主引用应用于v
[1,2,3,4,5].forEach { self.someCall($0) }
let closure = { [weak self] (_ parameter:Int) in
guard let self = self else { return }
self.method(parameter)
}
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
}
}
}