La fermeture ne peut pas implicitement la capture d'une mutation de l'auto paramètre
Je suis à l'aide de Firebase pour observer l'événement, puis la configuration d'une image à l'intérieur de gestionnaire d'achèvement
FirebaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.img = UIImage(named:"Some-image")!
} else {
self.img = UIImage(named: "some-other-image")!
}
})
Cependant j'obtiens cette erreur
De fermeture ne peut pas implicitement la capture d'une mutation de l'auto paramètre
Je ne suis pas sûr de ce que cette erreur est d'environ et la recherche de solutions n'a pas aidé
- Dans quel milieu vous appelez FirebaseRef.observeSingleEvent . Est-il appelé dans un struct?
- Oui elle est appelée à l'intérieur d'une struct
Vous devez vous connecter pour publier un commentaire.
La version courte
Le type de posséder votre appel à
FirebaseRef.observeSingleEvent(of:with:)
est probablement un type de valeur (unestruct
?), dans ce cas, une mutation du contexte peut ne pas explicitement captureself
dans un@escaping
fermeture.La solution la plus simple est de mettre à jour votre propriétaire type de référence une fois (
class
).La version longue
La
observeSingleEvent(de:avec:)
méthode de Firebase est déclarée comme suitLa
block
fermeture est marqué avec le@escaping
attribut de paramètre, ce qui signifie qu'il peut quitter le corps de sa fonction, et même la durée de vie deself
(dans ce contexte). Grâce à cette connaissance, nous construisons un plus minime exemple que nous pouvons analyser:Maintenant, le message d'erreur devient de plus en plus d'histoires, et nous nous tournons vers l'évolution suivante de la proposition a été mis en œuvre dans Swift 3:
@noescape
contextesIndiquant [c'est moi qui souligne]:
Maintenant, c'est un point clé. Pour un valeur type (par exemple,
struct
), je crois que c'est également le cas pour le type qui possède l'appel àobserveSingleEvent(...)
dans votre exemple, une telle explicite de capture n'est pas possible, autant que je sache (puisque nous travaillons avec un type de valeur, et non une référence à l'un).La solution la plus simple à ce problème serait de faire le type de propriétaire de la
observeSingleEvent(...)
un type de référence, par exemple unclass
, plutôt que d'unstruct
:Méfiez-vous cependant que cela permettra de capturer des
self
par une référence forte; en fonction de votre contexte (je n'ai pas utilisé Firebase moi-même, donc je ne sais pas), vous pouvez explicitement captureself
faiblement, par exempleself
dans@escape
blocs, vous pouvez mettre fin à la rétention des cycles qui peuvent provoquer des fuites de mémoire. Mieux utiliser[weak self]
(ou[unowned self]
si vous êtes sur le bloc du cycle de vie) dans tous les@escape
blocs de captureself
.Solution De Synchronisation
Si vous avez besoin de muter un type de valeur (
struct
) par une fermeture, qui ne peut fonctionner de manière synchrone, mais pas pour les appels asynchrones, si vous l'écrire comme ceci:Vous ne pouvez pas capturer une "mutation de soi" avec des types de valeur, sauf en fournissant une mutable (d'où
var
) copie.Pourquoi pas Async?
La raison pour laquelle cela ne fonctionne pas dans async contextes: vous pouvez encore muter
result
sans erreur de compilation, mais vous ne pouvez pas affecter la mutation résultat retour àself
. Encore, il n'y aura pas d'erreur, maisself
ne changera jamais parce que la méthode (peel()
) sorties avant la fermeture est encore distribué.Pour contourner cela, vous pouvez essayer de modifier votre code pour modifier l'appel asynchrone synchrone exécution en attente pour elle à la fin. Bien que techniquement possible, c'est probablement ce qui défait le but de l'API asynchrone vous interagissez avec, et vous feriez mieux de changer votre approche.
Changer
struct
àclass
est techniquement son option, mais ne traite pas le problème réel. Dans notre exemple, il est tout à faitclass Banana
, sa propriété peut être modifiée de manière asynchrone qui-sait-quand. Qui pose des problèmes car il est difficile à comprendre. Vous êtes mieux de l'écriture d'un API du gestionnaire à l'extérieur du modèle lui-même et à fini de l'exécution de récupérer et de modifier le modèle objet. Sans plus de contexte, il est difficile de donner un exemple d'adaptation. (Je suppose que c'est le code du modèle en raisonself.img
est muté dans le cas des OP code.)L'ajout d'async "anti-corruption" objets peuvent aider
Je suis en train de réfléchir à quelque chose entre les lignes de ce:
BananaNetworkRequestHandler
exécute des demandes de manière asynchrone et puis les rapports résultantBananaPeelingResult
retour à unBananaStore
BananaStore
puis prend les mesuresBanana
de son intérieur, en recherchant despeelingResult.bananaID
banana.bananaID == peelingResult.bananaID
, il définit ensuitebanana.isPeeled = peelingResult.isPeeled
,Vous voyez, de la quête de trouver une solution simple, il peut devenir très impliqué facilement, surtout si les modifications nécessaires comprennent l'évolution de l'architecture de l'application.
Si quelqu'un est tomber sur cette page (à partir de la recherche) et de la définition d'un
protocol
/protocol extension
, alors il pourrait être utile si vous déclarez votreprotocol
comme de classe lié. Comme ceci:var _self = self and setting
_self.propriété". Je vais essayer cette solution.Vous pouvez l'essayer! J'espère pouvoir vous aider.
Une autre solution est explicitement capture de soi (puisque dans mon cas, j'étais dans une mutation de la fonction d'une extension du protocole, donc je ne pouvais pas facilement spécifier que c'était un type de référence).
Ainsi, au lieu de cela:
J'ai ceci:
Qui semble avoir réduit au silence de l'avertissement.
Noter que cela ne fonctionne pas pour les types de valeur de sorte que si l'autonomie est une valeur de type dont vous avez besoin à l'aide d'une référence de type wrapper pour que cette solution fonctionne.
closureSelf
'sproperty
seranewValue
et le votre, ne changera pas. Heureux de débogage.