Dans mon TextViewTableViewCell
, j'ai une variable pour garder la trace d'un bloc et une méthode de configuration où le bloc est passé et attribué.
Voici ma TextViewTableViewCell
classe:
//
// 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)
}
}
}
Lorsque j'utilise la méthode configure dans ma méthode cellForRowAtIndexPath
, comment puis-je utiliser correctement le moi faible dans le bloc par lequel je passe.
Voici ce que j'ai sans moi faible:
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: Les éléments suivants ont été utilisés avec [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
Lorsque je fais [unowned self]
au lieu de [weak self]
et que je retire l'instruction if
, l'application se bloque. Des idées sur la façon dont cela devrait fonctionner avec [unowned self]
?
Si self peut être nul dans la fermeture, utilisez [self faible].
Si self ne sera jamais nul dans la fermeture, utilisez [non propriétaire]].
S'il se bloque lorsque vous utilisez [[moi non possédé]], je suppose que le soi est nul à un moment donné dans cette fermeture, c'est pourquoi vous avez dû choisir [faible moi] au lieu.
J'ai vraiment aimé toute la section du manuel sur l'utilisation de strong, faible et sans propriétaire dans les fermetures:
Remarque: j'ai utilisé le terme fermeture au lieu de bloc qui est le plus récent Swift terme:
Différence entre bloc (objectif C) et fermeture (Swift) dans iOS
Mettez [unowned self]
avant (text: String)...
dans votre fermeture. Ceci s'appelle un liste de capture et place des instructions de propriété sur les symboles capturés dans la fermeture.
** Édité pour Swift 4.2:
Comme @Koen a commenté, Swift 4.2 permet:
guard let self = self else {
return // Could not get a strong reference for self :`(
}
// Now self is a strong reference
self.doSomething()
P.S .: Puisque j'ai quelques votes positifs, je voudrais recommander la lecture à propos de échappées de clôture .
EDITED: Comme @ tim-vermeulen a commenté, Chris Lattner a déclaré le vendredi 22 janvier à 19:51:29 CST 2016, que cette astuce ne devrait pas être utilisée sur soi-même, donc s'il vous plaît ne l'utilisez pas. Vérifiez les informations sur les fermetures non d'échappement et la réponse à la liste de capture de @gbk. **
Pour ceux qui utilisent [faible moi] dans la liste de capture, notez que le moi pourrait être nul, donc la première chose que je fais est de vérifier cela avec une déclaration de garde
guard let `self` = self else { return } self.doSomething()
Si vous vous demandez ce que sont les guillemets, self
est une astuce qui permet d’utiliser soi-même à l’intérieur de la fermeture sans avoir à changer le nom en this , faibleSelf ou autre chose.
Utiliser liste de capture
Définition d'une liste de captures
Chaque élément d'une liste de capture est une association du mot clé faible ou non propriétaire avec une référence à une instance de classe (telle que self) ou une variable initialisée avec une valeur (telle que delegate = self.delegate!). Ces paires sont écrites dans une paire d'accolades carrées, séparées par des virgules.
Placez la liste de capture avant la liste de paramètres de fermeture et le type de retour s’ils sont fournis:
lazy var someClosure: (Int, String) -> String = {
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
// closure body goes here
}
Si une fermeture ne spécifie pas de liste de paramètres ni de type de retour car ils peuvent être déduits du contexte, placez la liste de capture au tout début de la fermeture, suivie du mot clé in:
lazy var someClosure: Void -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
}
EDIT: référence à une solution mise à jour par LightMan
Voir solution de LightMan . Jusqu'à présent j'utilisais:
input.action = { [weak self] value in
guard let this = self else { return }
this.someCall(value) // 'this' isn't nil
}
Ou:
input.action = { [weak self] value in
self?.someCall(value) // call is done if self isn't nil
}
Généralement, vous n'avez pas besoin de spécifier le type de paramètre s'il est inféré.
Vous pouvez tout à fait omettre le paramètre s'il n'y en a pas ou si vous vous y référez en tant que $0
dans la fermeture:
input.action = { [weak self] in
self?.someCall($0) // call is done if self isn't nil
}
Juste pour être complet; si vous passez la fermeture d'une fonction et que le paramètre n'est pas @escaping
, vous n'avez pas besoin d'un 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
}()
Vous pouvez utiliser [moi faible] ou [moi non possédé] dans la liste de capture avant vos paramètres du bloc. La liste de capture est une syntaxe facultative.
[unowned self]
fonctionne bien ici car la cellule ne sera jamais nulle. Sinon, vous pouvez utiliser [weak self]
Si vous vous écrasez, il vous faut probablement [auto faible]
Mon hypothèse est que le bloc que vous créez est en quelque sorte toujours câblé.
Créez un prepareForReuse et essayez d'effacer le bloc onTextViewEditClosure à l'intérieur de celui-ci.
func prepareForResuse() {
onTextViewEditClosure = nil
textView.delegate = nil
}
Voir si cela empêche le crash. (C'est juste une supposition).