161

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メソッドを使用する場合、渡すブロックでweak selfを適切に使用するにはどうすればよいですか。weak 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

更新:次を使用して動作するようになりました[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]ますか?

4

11 に答える 11

33

** 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 からの非エスケープ クロージャ情報とキャプチャ リストの回答を確認してください。**

キャプチャ リストで [weak self] を使用する場合は、self が nil になる可能性があることに注意してください。最初に行うことは、ガード ステートメントで確認することです。

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

引用符が何であるか疑問に思っている場合は、名前をthisweakSelfselfなどに変更する必要なく、クロージャー内で self を使用するプロのトリックです。

于 2016-07-28T11:37:37.593 に答える
33

閉鎖の[unowned self]前に置きます。(text: String)...これはキャプチャ リストと呼ばれ、クロージャでキャプチャされたシンボルに所有権の指示を配置します。

于 2014-06-28T16:11:18.593 に答える
33

編集: 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) }
于 2016-12-14T12:12:16.120 に答える
26

キャプチャリストを使用

キャプチャ リストの定義

キャプチャ リストの各項目は、weak または unowned キーワードと、クラス インスタンス (self など) または値で初期化された変数 (delegate = self.delegate! など) への参照とのペアです。これらのペアリングは、コンマで区切られた 1 対の角括弧内に記述されます。

キャプチャ リストをクロージャのパラメータ リストの前に配置し、型が提供されている場合は型を返します。

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
}

追加説明

于 2015-10-19T09:22:05.017 に答える
3

ブロックのパラメータの前に、キャプチャ リストで [weak self] または [unowned self] を使用できます。キャプチャ リストはオプションの構文です。

[unowned self]セルが nil になることはないため、ここではうまく機能します。それ以外の場合は使用できます[weak self]

于 2014-06-28T16:19:39.420 に答える
1

から、クロージャの前に渡す場合、クロージャでSwift 5.3アンラップする必要はありません。self[self]in

この迅速なドキュメントを参照someFunctionWithEscapingClosure { [self] in x = 100 }してください

于 2021-02-21T15:41:19.400 に答える
0

必要以上にクラッシュしている場合【弱い自分】

私の推測では、あなたが作成しているブロックは何らかの形でまだ接続されています。

prepareForReuse を作成し、その中の onTextViewEditClosure ブロックをクリアしてみてください。

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

それがクラッシュを防ぐかどうかを確認してください。(これは単なる推測です)。

于 2015-05-11T20:01:29.827 に答える