私の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]
でどのように機能するかについてのアイデアはありますか?
selfがクロージャでゼロになる可能性がある場合は、[weak self]を使用してください。
selfがクロージャの中で決してnilにならない場合--- [unowned self]を使ってください。
[unowned self]を使ったときにクラッシュしたら、selfはそのクロージャのどこかの時点でnilになると思いますので、[weak self]代わりに。
マニュアルの中でstrong、weak、そしてnownedをクロージャで使うことについてのセクション全体が本当に気に入りました。
注:私はより新しいSwift用語であるblockの代わりにclosureという用語を使用しました。
クロージャーの[unowned self]
の前に(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()
P.S .:私はいくつかの賛成票を持っているので、 閉鎖のエスケープ について読むことをお勧めします。
編集:@ tim-vermeulenがコメントしているように、Chris LattnerはFri Jan 22 19:51:29 CST 2016で、このトリックは自分で使用すべきではないので使用しないでください。 @gbkからの非エスケープクロージャ情報とキャプチャリストの答えをチェックしてください。**
捕獲リストで[弱い自己]を使う人たちのために、自己がゼロである可能性があることに注意してください、それで私が最初にすることは保護声明でそれをチェックすることです
guard let `self` = self else { return } self.doSomething()
引用符の周囲に疑問がある場合は、名前をthis、weakSelfに変更せずにクロージャー内でselfを使用することをお勧めします。self
あるいは何でも。
キャプチャリスト を使用
キャプチャリストの定義
キャプチャリストの各項目は、クラスインスタンス(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
}
編集: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)
}
_ = { [weak self] value in
guard let self = self else { return }
print(self) //???? will never be nil
}()
あなたはブロックのあなたのパラメータの前に捕獲リストで[弱い自己]または[未所有の自己]を使うことができます。キャプチャリストはオプションの構文です。
ここでは[unowned self]
がうまくいきますが、これはセルがゼロになることは決してないからです。そうでなければ[weak self]
を使うことができます
あなたがクラッシュするのであれば、おそらく必要以上に必要です[弱い自己]
私が推測しているのは、あなたが作成しているブロックはまだ何らかの形で配線されているということです。
PrepareForReuseを作成し、その中のonTextViewEditClosureブロックをクリアしてみてください。
func prepareForResuse() {
onTextViewEditClosure = nil
textView.delegate = nil
}
それがクラッシュを防ぐかどうかを確認してください。 (それは単なる推測です)。