2016-08-02 3 views
1

Я экспериментирую с управлением памятью в Swift следующим образом.нужна ли нам слабая или неопубликованная ссылка при выполнении ленивой переменной, управление памятью

class Person { 
    let name: String 
    //var block: (() -> Void)? 

    init(name: String) { 
     self.name = name 
    } 

    // Declare variable clone, using self inside. 
    private lazy var clone: String = { 
     return self.name 
    }() 

    deinit { 
     print("Destroying \(name)") 
    } 
    func doSomething() { 
     print("Doing something for \(name)") 
    } 
} 

var p2: Person? = Person(name: "p2") 
print(p2!.clone) 
p2 = nil 

Как вы видите, я использую self внутри при объявлении ленивого вара, и я думаю, что это еще хорошо, потому что, когда p2 получает ноль, я могу видеть, метод deinit дозвонился.

Однако, если внести изменения, как следующий

// This is a closure 
    private lazy var clone:() -> String = { 
     return self.name // leaking memory is here 
    } 

Теперь я получаю протечки памяти.

Мой вопрос предназначен для переменной, использующей ленивую инстанцирование, поэтому я не получаю утечку памяти, хотя я использую self. Я думал, что должен использовать ее, иначе я получаю утечку памяти.

ответ

1

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

+0

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

6

Здесь:

private lazy var clone:() -> String = { 
     return self.name // leaking memory is here 
    } 

Вы назначаете замыкание сам к переменной, вместо того, присваивая String, что он должен вернуться. И так как вы используете self, который закрывает , он сохраняет, два никогда не будут выпущены, что может привести к memory leak. A reference cycle создается, поскольку закрытие сохраняется как свойство, а замыкание сохраняется. Здесь вы видите capture lists. Вы можете зафиксировать утечку следующим образом:

private lazy var clone:() -> String = { [unowned self] in 

     return self.name // leaking memory is fixed 
    } 

Self объявлен как unowned в capture lists, как это можно предположить, что она будет НЕ быть nil в любой момент. Если вы уверены, что переменная будет НЕ быть nil, используйте unowned, но если вы думаете, в какой-то момент может статьnil, используйте weak вместо этого.