Подтвердить что ты не робот

Доступ к свойствам экземпляра экземпляра, который является закрытием

Я использую 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 {...} для вычисленного свойства, если оно только gettable.)

Итак, первое замыкание self похоже на сам тип функции/замыкания, тогда как другие self относятся к контроллеру представления (как и следовало ожидать). Единственное различие между c1 и c2/c3 состоит в том, что первое является сохраненным свойством, последние являются вычисленными свойствами, но я все же ожидал бы, что замыкания и их зафиксированные значения будут одинаковыми, т.е. self всегда обратитесь к прилагаемому классу. Теперь, похоже, нет очевидного способа закрытия c1 для доступа к методам/свойствам окружающего класса.

Я где-то это где-то документировал (я читал книгу Swift и ничего не нашел), или это просто ошибка в бета-компиляторе, которую нужно где-то подавать?

4b9b3361

Ответ 1

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

Свойство lazy означает, что вы можете ссылаться на self в закрытии по умолчанию, потому что свойство lazy не будет доступно до тех пор, пока не будет завершена инициализация и известно, что 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 был изменен на ленивый