如何正确处理带参数的Swift块中的弱自我

Nat*_*bot 143 ios retain-cycle swift

在我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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当我在我的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
Run Code Online (Sandbox Code Playgroud)

更新:我使用以下工作[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
Run Code Online (Sandbox Code Playgroud)

当我做[unowned self]而不是[weak self]取出if声明时,应用程序崩溃了.关于这应该如何使用的任何想法[unowned self]

Ten*_*Jay 176

如果封闭使用自我可能是零[弱自我].

如果自我永远不会在闭包中使用[无主自我].

如果你在使用[无主自我]时崩溃了,我猜在封闭的某个时刻自我是零,这就是为什么你不得不选择[弱自我].

我非常喜欢手册中有关使用,封闭的手册的整个部分:

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html

注意:我使用了术语closure而不是block,这是更新的Swift术语:

ios中块(目标C)和闭包(Swift)之间的区别

  • Apple在他们的第一个C语言扩展文档中称为块"闭包".(块或闭包是最初的C的扩展.只有MM与Objective-C有关.)即使我更喜欢术语"闭包",因为C中的"块"经常与复合语句相关,它在两种语言中都是一种错误,因为它被称为闭包,即使它不会关闭一个对象(变量或常量). (7认同)
  • 我建议永远不要使用“unowned”。不值得冒导致应用程序崩溃的风险。 (2认同)

iku*_*dia 30

放在你的关闭[unowned self]之前(text: String)....这称为捕获列表,并将所有权指令放在闭包中捕获的符号上.

  • 我不认为这个答案是有用的.如果在执行关闭期间self变为nil,[unowned self]将崩溃 (3认同)
  • 绝对没有理由**除了(1)在非常*异常的情况下,使用无主要的表现(这在这里和99.999%的编程完全不相关)和(2)作为一种风格执行问题.声明"你应该总是使用弱者,从不拥有"是非常合理的. (3认同)
  • 谢谢你的命名,我想知道! (2认同)

Lig*_*Man 28

编辑:正如@ tim-vermeulen评论的那样,Chris Lattner在2016年1月22日星期五19:51:29 CST表示,这个技巧不应该用于自我,所以请不要使用它.检查@gbk中的非转义闭包信息和捕获列表答案.

对于那些在捕获列表中使用[弱自我]的人,请注意self可以是nil,所以我要做的第一件事就是用一个保护声明来检查

guard let self = self else {
   return // Could not get a strong reference for self :`(
}

// Now self is a strong reference
self.doSomething()
Run Code Online (Sandbox Code Playgroud)

如果你想知道引号是什么,那么self在闭包中使用self是一个专业技巧,而不需要将名称改为this,weakSelf或其他.

PS:由于我有一些上涨票,我想推荐关于非逃避封闭的阅读.TL; DR大多数方法最后调用由参数传递的闭包,如果是这种情况你可以在闭包参数中使用@noescape,你可以在闭包中隐式引用.

  • `self`是一个阴影样本,有关它的文章可以在这里找到http://arsenkin.com/swift-closure-without-ugly-strongSelf.html (2认同)
  • 我倾向于称当地的"自我"为"强自我",以确保它不会与默认的自我混淆,更容易发现你是否已经保护自己的强大自我参考. (2认同)

gbk*_*gbk 26

使用捕获列表

定义捕获列表

捕获列表中的每个项目都是弱或无主关键字与对类实例(如self)的引用或使用某个值初始化的变量(如delegate = self.delegate!)的配对.这些配对写在一对方括号内,用逗号分隔.

将捕获列表放在闭包的参数列表之前,如果提供了它们,则返回类型:

lazy var someClosure: (Int, String) -> String = {
    [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
    // closure body goes here 
} 
Run Code Online (Sandbox Code Playgroud)

如果闭包没有指定参数列表或返回类型,因为它们可以从上下文中推断出来,请将捕获列表放在闭包的最开头,然后是in关键字:

lazy var someClosure: Void -> String = {
    [unowned self, weak delegate = self.delegate!] in
    // closure body goes here
}
Run Code Online (Sandbox Code Playgroud)

其他解释

  • 你使用"自我"无所谓,这意味着当你访问它时,你肯定知道"自我"不会是零.然后你使用force unwrap on"self.delegate"(这也意味着你肯定知道它不会是nil)将它分配给弱变量.如果你肯定知道"self.delegate"不会是零,为什么不在"委托"而不是弱者上使用无主? (3认同)

Fer*_*nch 24

编辑:删除"自我"技巧

由于不建议使用LightMan的解决方案,我通常会这样做:

input.action = { [weak self] value in
    guard let this = self else { return }
    this.someCall(value) // 'this' isn't nil
}
Run Code Online (Sandbox Code Playgroud)

要么:

input.action = { [weak self] value in
    self?.someCall(value) // call is done if self isn't nil
}
Run Code Online (Sandbox Code Playgroud)

通常,如果推断出参数类型,则无需指定参数类型.

如果没有参数,或者如果$0在闭包中引用参数,则可以完全省略参数:

input.action = { [weak self] in
    self?.someCall($0) // call is done if self isn't nil
}
Run Code Online (Sandbox Code Playgroud)

只是为了完整; 如果您将闭包传递给函数而参数不是@escaping,则不需要weak self:

[1,2,3,4,5].forEach { self.someCall($0) }
Run Code Online (Sandbox Code Playgroud)


Ala*_*osh 8

斯威夫特4.2

let closure = { [weak self] (_ parameter:Int) in
    guard let self = self else { return }

    self.method(parameter)
}
Run Code Online (Sandbox Code Playgroud)

https://github.com/apple/swift-evolution/blob/master/proposals/0079-upgrade-self-from-weak-to-strong.md


eon*_*ist 7

从Swift 4.2开始,我们可以:

_ = { [weak self] value in
    guard let self = self else { return }
    print(self) // will never be nil
}()
Run Code Online (Sandbox Code Playgroud)

  • 从Swift 4.2开始,您可以使用`guard let self = self else {return}`来解开[[weak self]`:https://github.com/apple/swift-evolution/blob/master/proposals/0079-upgrade从弱到强.md (3认同)