#swift
#swift
Вопрос:
Я использую Xcode6-beta2, но у меня была такая же проблема с самого первого публичного бета-тестирования. Мой подкласс Swift Obj-C UIViewController выглядит следующим образом:
class SomeVC: UIViewController {
var c1: () -> () = {
println(self)
}
var c2: () -> () {
get {
return { println(self) }
}
}
var c3: () -> () {
return { println(self) }
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
c1()
c2()
c3()
}
}
Когда отображается VC, я вижу распечатанные следующие строки:
(Function)
<_TtC12SwiftiOSTest6SomeVC: 0x10bf1ed10>
<_TtC12SwiftiOSTest6SomeVC: 0x10bf1ed10>
(c2 и c3 отличаются только тем, что нет необходимости включать get {…} для вычисляемого свойства, если оно доступно только для получения.)
Итак, self первого замыкания, похоже, относится к самому типу функции / замыкания, тогда как self других относится к контроллеру представления (как я и ожидал). Единственное различие между c1 и c2 / c3 заключается в том, что первое является сохраненным свойством, последние являются вычисляемыми свойствами, но я все равно ожидаю, что замыкания и их захваченные значения будут одинаковыми, т. Е. self всегда будет ссылаться на окружающий класс. Похоже, что сейчас нет очевидного способа для закрытия c1 получить доступ к методам / свойствам окружающего класса.
Это что-то задокументированное где-то (я прочитал книгу Swift и ничего не нашел), или это просто какая-то ошибка бета-компилятора, которая должна быть где-то зарегистрирована?
Ответ №1:
Это выглядит интересно, поэтому я копаю немного глубже. Обнаружил, что вы можете получить доступ к переменным экземпляра класса внутри замыкания, например self.instanceVariable
. Тогда замыкание захватит self
его внутри. Итак, теперь self
это относится к самому экземпляру класса. Ваше закрытие должно быть отложенным свойством.
Отложенное свойство означает, что вы можете ссылаться на self в замыкании по умолчанию, потому что к отложенному свойству не будет доступа до тех пор, пока не будет завершена инициализация и не станет известно, что self существует.
Вам не хватает @lazy, так что self
это неизвестно закрытию, поэтому оно печатает его, как (Function)
я предполагаю.
class TableViewController: UIViewController {
var name = "anil"
// Since swift 2.0 came out @lazy is replaced by lazy
lazy var c1: () -> () = {
println(self)
println(self.name)
}
var c2: () -> () {
get {
return { println(self) }
}
}
var c3: () -> () {
return { println(self) }
}
override func viewDidLoad() {
super.viewDidLoad()
c1()
c2()
c3()
}
}
Вывод
<_TtC12TableViewApp19TableViewController: 0x10d54e000>
anil
<_TtC12TableViewApp19TableViewController: 0x10d54e000> <_TtC12TableViewApp19TableViewController: 0x10d54e000>
Обновить
Назначение замыкания переменной экземпляра класса приводит к сильному циклу ссылок. Вам следует избегать этого. Для этого Swift использует список захвата
Если вы назначаете замыкание свойству экземпляра класса, и замыкание захватывает этот экземпляр, ссылаясь на экземпляр или его члены, вы создадите сильный ссылочный цикл между замыканием и экземпляром. Swift использует списки захвата для разрыва этих сильных ссылочных циклов. Для получения дополнительной информации см. Сильные ссылочные циклы для замыканий.
Таким образом, правильное использование замыкания может быть
@lazy var c1: () -> () = {
[unowned self] in
println(self)
println(self.name)
}
Ссылка: руководство по программированию Swift
@lazy
Edit был изменен на lazy
Комментарии:
1. Я попробовал это, и я получил эту ошибку компилятора: ‘SomeVC -> () -> SomeVC!’ не имеет члена с именем ‘name’. Но ваш код отличается от моего еще в одном аспекте — @lazy keywoard / директива / что бы это ни было. Когда я добавляю это перед определением замыкания c1 , оно работает, мне даже не нужно имя var. Это еще более запутанно, какое отношение к чему-либо здесь имеет ленивый инициализация?
2. Так что это похоже на ошибку компилятора, не так ли?
3. Нет необходимости в переменной экземпляра, это было мое недоразумение. Вы можете опустить переменную. но требуется @lazy .
4. Хорошо, я нашел этот отрывок в книге Swift от Apple, так что это задокументировано без проблем с компилятором. Тем не менее, очень, очень запутанно. Спасибо за помощь в прояснении этого.
5. Да, я знаю об этом, и мой код на самом деле не использует сильные ссылки на self (я использую [слабый self], потому что unowned взорвался на мне, не знаю почему. Мне нужно еще раз прочитать главу ARC. Я не использовал его в своем первоначальном сообщении, чтобы упростить минимизацию беспорядка.