簡體   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