react - rxswift swift
Fuga de memoria de Strift rápida (3)
Estamos tratando de usar estructuras Swift donde podamos. También estamos utilizando RxSwift que tiene métodos que toman cierres. Cuando tenemos una estructura que crea un cierre que se refiere a uno mismo , eso crea un ciclo de referencia fuerte .
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)
}
}
¿Cómo puedo saber esto? Si creo 100,000 objetos de DoesItLeak y llamo a algunosFoo () en cada uno de ellos, creo que tengo 100,000 objetos con fuertes ciclos de referencia. En otras palabras, cuando me deshago de la matriz DoesItLeak que contiene esos objetos, los objetos permanecen en la memoria. Si no llamo a someFoo (), no hay problema.
La variable es una clase. Por lo tanto, puedo ver este problema de memoria utilizando las Asignaciones y el filtrado de los instrumentos de xcode en Variable <String>
Si trato de usar [yo débil] como en el siguiente, obtengo un error del compilador:
someVariable.subscribeNext { [weak self] person in
El error del compilador es "débil no se puede aplicar a un tipo que no sea de clase"
En código real / no de ejemplo, accedemos a métodos y variables a través de nosotros mismos y es un problema de memoria.
¿Cómo puedo resolver este problema de memoria mientras mantengo la estructura DoesItLeak?
Gracias por tu ayuda.
Como Darren puso en los comentarios: " DoesItLeak no puede ser una estructura " No podemos hacer que DoesItLeak
sea una estructura y resuelva de forma segura el problema del ciclo de referencia fuerte.
Los tipos de valor como estructuras existen en el marco de pila. Los cierres y las clases son tipos de referencia.
Como lo indica la sección Ciclos de referencia fuertes para cierres :
Este fuerte ciclo de referencia se produce porque los cierres, como las clases, son tipos de referencia.
Como la estructura tiene la clase Variable
y el cierre que se refiere a self
se almacena en la clase Variable
mediante subscribeNext
, crea el ciclo de referencia fuerte. Consulte "Resolución de ciclos de referencia sólidos para cierres" en la documentación de Apple del conteo automático de referencias .
El patrón de captura del yo por un cierre de escape en un contexto escribible ahora no está permitido. El compilador Swift emitirá un error "El cierre no puede capturar implícitamente un parámetro que está mutando". Si el contexto es de solo lectura, el valor de self podría copiarse o compartirse y, en cualquier caso, no habría un ciclo de referencia.
Para quien todavía se enfrenta a este problema.
1) [weak self]
no es posible porque Struct es un value type
y no un Reference type
, por lo que no hay puntero como tal.
2) El principal problema de la fuga aquí es que está intentando acceder a la propiedad self.someState = something
dentro del bloque de finalización que básicamente creará una nueva copia de su estructura en la asignación.
No debe acceder a la propiedad Struct dentro del bloque de finalización.