web-dev-qa-db-fra.com

Comment gérer correctement le moi faible dans Swift Blocs avec arguments

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]?

142
NatashaTheRobot

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:

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

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

175
TenaciousJay

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.

30
ikuramedia

** É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.

28
LightMan

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
}

explications supplémentaires

25
gbk

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) }
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

À partir de Swift 4.2 ???? nous pouvons faire:

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

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]

3
Rufus

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).

0
Michael Gray