Nous essayons d'utiliser les structures Swift dans la mesure du possible. Nous utilisons également RxSwift qui a des méthodes qui prennent des fermetures. Quand nous avons une structure qui crée une fermeture qui fait référence à self , cela crée un cycle de référence fort .
import Foundation
import RxSwift
struct DoesItLeak {
var someState: String = "initial value"
var someVariable: Variable<String> = Variable("some stuff")
let bag = DisposeBag()
mutating func someFoo() {
someVariable.subscribeNext { person in
self.someState = "something"
}
.addDisposableTo(bag)
}
}
Comment je sais ça? Si je crée 100 000 objets DoesItLeak et que j'appelle someFoo () sur chacun d'eux, je crois que j'ai 100 000 objets avec des cycles de référence puissants. En d'autres termes, lorsque je supprime le tableau DoesItLeak contenant ces objets, ceux-ci restent en mémoire. Si je n'appelle pas someFoo (), il n'y a pas de problème.
La variable est une classe. Donc, je peux voir ce problème de mémoire en utilisant les Allocations Instruments de xcode et en filtrant dans Variable <String>
Si j'essaie d'utiliser [moi faible] comme dans ce qui suit, j'obtiens une erreur de compilation:
someVariable.subscribeNext { [weak self] person in
L'erreur du compilateur est "faible ne peut pas être appliqué à un type non-classe"
En code réel/non-exemple, nous accédons à des méthodes et à des variables via self, c'est un problème de mémoire.
Comment puis-je résoudre ce problème de mémoire tout en conservant la structure DoesItLeak?
Merci de votre aide.
Comme Darren , mettez-le dans les commentaires: " DoesItLeak ne peut pas être une structure " Nous ne pouvons pas avoir la DoesItLeak
être une structure et résoudre en toute sécurité le problème du cycle de référence fort.
Les types de valeur tels que les structures existent sur le cadre de la pile. Les fermetures et les classes sont des types de référence.
Comme le dit le Section des cycles de référence puissants pour les fermetures :
Ce cycle de référence fort se produit car les fermetures, comme les classes, sont des types de référence.
Étant donné que la structure a la valeur Variable
class et que la fermeture faisant référence à self
est stockée dans la classe Variable
à l'aide de subscribeNext
, elle crée le cycle de référence fort. Voir "Résolution des cycles de référence importants pour les fermetures" dans Comptage automatique des références Documentation Apple.
Pour quiconque est toujours confronté à ce problème.
1) [weak self]
n'est pas possible car Struct est value type
et non un Reference type
, donc pas de pointeur en tant que tel.
2) Le problème principal de la fuite est que vous essayez d'accéder à la propriété Struct self.someState = something
à l'intérieur du bloc d'achèvement, ce qui créera une nouvelle copie de votre structure lors de l'affectation.
Vous ne devez pas accéder à la propriété Struct à l'intérieur du bloc d'achèvement.
Le schéma de capture de soi par une fermeture évasive dans un contexte accessible en écriture est maintenant interdit. Le compilateur Swift émettra une erreur "La fermeture ne peut pas capturer implicitement un paramètre auto en mutation". Si le contexte est en lecture seule, la valeur de self pourrait être copiée ou partagée et, dans les deux cas, il n'y aurait pas de cycle de référence.