Утечка памяти Swift Struct

Мы пытаемся использовать структуры Swift, где можем. Мы также используем RxSwift, у которого есть методы, которые принимают замыкания. Когда у нас есть структура, которая создает закрытие, которое ссылается на self, это создает сильный ссылочный цикл.

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

Откуда я знаю это? Если я создам 100 000 объектов DoItLeak и вызываю someFoo() для каждого из них, я считаю, что у меня есть 100 000 объектов с сильными ссылочными циклами. Другими словами, когда я избавляюсь от массива DoesItLeak, содержащего эти объекты, объекты остаются в памяти. Если я не вызываю someFoo(), проблем нет.

Переменная - это класс. Итак, я вижу эту проблему с памятью, используя привязки xcode Instruments и фильтрацию в переменной <String>

Filtering By Variable

enter image description here

Если я попытаюсь использовать [слабый я], например, в следующем, я получаю ошибку компилятора:

someVariable.subscribeNext { [weak self] person in

Ошибка компилятора "слабый не может применяться к типу некласса"

В реальном/нестандартном коде мы получаем доступ к методам и переменным через self и это проблема памяти.

Как я могу решить эту проблему с памятью, сохраняя структуру IsItLeak?

Спасибо за вашу помощь.

Ответы

Ответ 1

Как Даррен выразился в комментариях: " DoesItLeak не может быть структура " Мы не можем иметь DoesItLeak быть структура и безопасно решить проблему сильного опорного цикла.

Типы значений, такие как структуры, существуют в кадре стека. Закрытия и классы являются ссылочными типами.

Поскольку раздел " Сильные ссылочные циклы для закрытий" гласит:

Этот сильный ссылочный цикл происходит потому, что замыкания, подобные классам, являются ссылочными типами.

Поскольку структура имеет класс Variable а замыкание, относящееся к self, сохраняется в классе Variable используя subscribeNext, он создает сильный ссылочный цикл. См. "Разрешение сильных ссылочных циклов для закрытий" в документе " Автоматическое сопоставление ссылок по документам Apple".

Ответ 2

Образ захвата "я" с помощью экранирующего закрытия в доступном для записи контексте теперь запрещен. Быстрое компилятор выдает ошибку "Закрытие не может неявно захватывать параметр mutating self". Если контекст доступен только для чтения, значение self может быть скопировано или разделено, и в любом случае не будет эталонного цикла.