Быстрая проблема при хранении объекта внутри структуры - PullRequest
0 голосов
/ 28 октября 2019

Я запутался в том, как здесь управляют памятью, допустим, есть сценарий:

import Foundation

class SomeObject {
    deinit {
        print("deinitCalled")
    }
}
struct SomeStruct {
    let object = SomeObject()
    var closure: (() -> Void)?
}

func someFunction() {
    var someStruct = SomeStruct()
    someStruct.closure = {
        print(someStruct)
    }
    someStruct.closure?()
}
someFunction()
print("the end")

Что я мог бы ожидать здесь:

Optional(test.SomeStruct(object: test.SomeObject, closure: Optional((Function))))
deinitCalled
the end

Однако я получаюэто:

SomeStruct(object: test.SomeObject, closure: Optional((Function)))
the end

И если я посмотрю на карту памяти:

enter image description here

сохранить цикл

Как мне управлять памятью в этом случае

1 Ответ

3 голосов
/ 28 октября 2019

Во-первых, вы должны быть очень, очень осторожны при размещении ссылочных типов внутри типов значений, и особенно изменяемого ссылочного типа, видимого для внешнего мира. Структуры всегда являются типами значений, но вы также хотите, чтобы они имели значение семантика , и это сложно сделать при наличии ссылочных типов. (Это очень возможно, многие типы stdlib делают это для реализации копирования при записи; это просто сложно.)

Итак, короткая версия: «Вы почти наверняка не хотите делать то, что вы»Вы делаете здесь. "

Но если вы сохранили семантику значений в SomeStruct, то ответом будет просто сделать копию. Всегда хорошо сделать копию типа значения.

someStruct.closure = { [someStruct] in
    print(someStruct)
}

Это дает закрытию его собственное неизменное значение, которое является копией someStruct. Будущие изменения в someStruct не повлияют на это закрытие.

Если вы имеете в виду для будущих изменений в someStruct, чтобы повлиять на это закрытие, то вы можете нарушать семантику значений, и выдолжен изменить дизайн (вероятно, сделав SomeStruct классом, если вы хотите, чтобы он имел ссылочную семантику).

...