2016-09-13 3 views
6

У меня есть пример:список Захват в Swift

class Animal { 
    var stamina = 0 

    func increaseStamina() { 
     stamina += 1 
    } 
} 

var a = Animal() 

var closure = { [weak a] in 
    a?.stamina = 10 
} 

a.stamina // 0 
a.increaseStamina() 
a.stamina // 1 
closure() 
a.stamina // 10 

если изменить closure так:

var closure = { [weak a] in 
    a = Animal() 
    a?.stamina = 10 
} 

то печатает что-то вроде этого:

a.stamina // 0 
a.increaseStamina() 
a.stamina // 1 
closure() 
a.stamina // 1 

Почему последняя строка отличается?

+0

Возможный дубликат [Как блокировки фиксируют значения из предыдущих вызовов?] (Http://stackoverflow.com/questions/37839020/how-do-closures-capture-values-from-previous-calls) – Honey

+1

@Honey: Я не уверен, что это дубликат. Это связано, но в этом вопросе нет списков захвата, и нет классов (ссылочных типов). –

+0

@MartinR Ohhhhk – Honey

ответ

5

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

В вашем случае

var closure = { [weak a] in 
    a = Animal() 
    a?.stamina = 10 
} 

a внутри закрытия инициализируется со слабой ссылкой на Animal объект, созданный ранее, но это не зависит от внешней a переменной. a = Animal() создает новый экземпляр и присваивает ссылку этой локальной переменной a. Поскольку это слабое задание, объект освобождается немедленно (вы можете проверить, что , добавив print(a) в закрытие). Внешняя переменная a по-прежнему ссылается на исходный объект:

print(a.stamina) // 0 
a.increaseStamina() 
print(a.stamina) // 1 
print(ObjectIdentifier(a)) // ObjectIdentifier(0x0000000100a03060) 
closure() 
print(ObjectIdentifier(a)) // ObjectIdentifier(0x0000000100a03060) 
print(a.stamina) // 1 

Если опустить список захвата затем a внутри затвора и снаружи закрытия обратиться к одной и той же переменной, и новый экземпляр может быть назначен внутри закрытие:

var a = Animal() 

var closure = { 
    a = Animal() 
    a.stamina = 10 
} 

print(a.stamina) // 0 
a.increaseStamina() 
print(a.stamina) // 1 
print(ObjectIdentifier(a)) // ObjectIdentifier(0x0000000100b06ac0) 
closure() 
print(ObjectIdentifier(a)) // ObjectIdentifier(0x0000000100e00070) 
print(a.stamina) // 10 

Для получения дополнительной информации и получения дополнительной информации см "Capture Lists" в Swift ссылок (спасибо так @Arthur для обеспечения ссылки).

+2

Так как мне было любопытно, [вот соответствующая часть в справочной системе Apple Swift (Swift 2.2)] (https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions .html # // apple_ref/doc/uid/TP40014097-CH32-ID544): «Для каждой записи в списке захвата константа инициализируется значением * * константы или переменной, которая имеет то же имя в окружающей области [...] " – Arthur

+0

@ Артур: Спасибо! - Мне просто интересно, почему в документации говорится: «... константа инициализирована ...» *. В этом случае слабо зафиксированная ссылка, 'a' является * переменной * в замыкании. –

+0

Привет @MartinR, почему 'var clos = {[слабый a] в a? .stamina = 10 }' дайте мне 'a.stamina' // 10, потому что вы говорите' a' в закрытии зависимость от ' a' за закрытием. – Khuong

Смежные вопросы