web-dev-qa-db-ja.com

引数付きのSwiftブロックで弱い自己を正しく処理する方法

私の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をどのように使用するのですか。
ここに私は弱い自己なしで持っているものがあります:

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

UPDATE:私は[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]でどのように機能するかについてのアイデアはありますか?

139
NatashaTheRobot

selfがクロージャでゼロになる可能性がある場合は、[weak self]を使用してください。

selfがクロージャの中で決してnilにならない場合--- [unowned self]を使ってください。

[unowned self]を使ったときにクラッシュしたら、selfはそのクロージャのどこかの時点でnilになると思いますので、[weak self]代わりに。

マニュアルの中でstrongweak、そしてnownedをクロージャで使うことについてのセクション全体が本当に気に入りました。

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

注:私はより新しいSwift用語であるblockの代わりにclosureという用語を使用しました。

iosにおけるブロック(Objective C)とクロージャ(Swift)の違い

174
TenaciousJay

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

30
ikuramedia

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

P.S .:私はいくつかの賛成票を持っているので、 閉鎖のエスケープ について読むことをお勧めします。

編集:@ tim-vermeulenがコメントしているように、Chris LattnerはFri Jan 22 19:51:29 CST 2016で、このトリックは自分で使用すべきではないので使用しないでください。 @gbkからの非エスケープクロージャ情報とキャプチャリストの答えをチェックしてください。**

捕獲リストで[弱い自己]を使う人たちのために、自己がゼロである可能性があることに注意してください、それで私が最初にすることは保護声明でそれをチェックすることです

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

引用符の周囲に疑問がある場合は、名前をthisweakSelfに変更せずにクロージャー内でselfを使用することをお勧めします。selfあるいは何でも。

26
LightMan

キャプチャリスト を使用

キャプチャリストの定義

キャプチャリストの各項目は、クラスインスタンス(selfなど)への参照または何らかの値で初期化された変数(delegate = self.delegate!など)を含むweakまたはunownedキーワードのペアです。これらの組み合わせは、コンマで区切られた一対の角括弧で囲まれています。

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

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
}

補足説明

25
gbk

編集: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) }
24
Ferran Maylinch

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

8
Alan McCosh

Swift 4.2以降。我々はできる:

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

あなたはブロックのあなたのパラメータの前に捕獲リストで[弱い自己]または[未所有の自己]を使うことができます。キャプチャリストはオプションの構文です。

ここでは[unowned self]がうまくいきますが、これはセルがゼロになることは決してないからです。そうでなければ[weak self]を使うことができます

3
Rufus

あなたがクラッシュするのであれば、おそらく必要以上に必要です[弱い自己]

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

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

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

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

0
Michael Gray