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
        }
    }
}
  • -更可取的做法是,在可能时使用它
  • unowned
    -当您确定实例所有者的生存期大于closure时使用它

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
        }
    }
}