繁体   English   中英

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

[英]How to Correctly handle Weak Self in Swift Blocks with Arguments

在我的TextViewTableViewCell ,我有一个变量来跟踪块和一个configure方法,其中传入和分配块。
这是我的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)
        }
    }
}

当我在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

更新 :我使用[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

当我做[unowned self]而不是[weak self]并取出if语句时,应用程序崩溃了。 关于如何与[unowned self]合作的任何想法?

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

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

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

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

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

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

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

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

**为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()

PS:由于我有一些上涨票,我想推荐关于逃避封闭的阅读。

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

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

 guard let `self` = self else { return } self.doSomething() 

如果你想知道引号是什么周围的self是一个专业技巧,在封闭中使用self而无需将名称更改为thisweakSelf或其他。

使用捕获列表

定义捕获列表

捕获列表中的每个项都是弱或无主关键字与对类实例(如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 
} 

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

lazy var someClosure: Void -> String = {
    [unowned self, weak delegate = self.delegate!] in
    // closure body goes here
}

其他解释

编辑:参考LightMan的更新解决方案

请参阅LightMan的解决方案 到现在为止我正在使用:

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

要么:

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

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

如果没有参数,或者在闭包中将其称为$0 ,则可以完全省略参数:

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

只是为了完整; 如果你将闭包传递给函数并且参数不是@escaping ,那么你不需要weak self

[1,2,3,4,5].forEach { self.someCall($0) }

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

从快速4.2🔸我们可以做到:

_ = { [weak self] value in
    guard let self = self else { return }
    print(self) //👈 will never be nil
}()

您可以在块的参数之前在捕获列表中使用[weak self]或[unowned self]。 捕获列表是可选语法。

[unowned self]在这里运作良好,因为细胞永远不会是零。 否则你可以使用[weak self]

如果你的崩溃比你可能需要[弱自我]

我的猜测是你正在创建的块仍然以某种方式连线。

创建一个prepareForReuse并尝试清除其中的onTextViewEditClosure块。

func prepareForResuse() {
   onTextViewEditClosure = nil
   textView.delegate = nil
}

看看是否可以防止崩溃。 (这只是猜测)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM