Какая разница для включения (или не включения) списка захвата в неэкранированные замыкания? - PullRequest
1 голос
/ 05 марта 2019

Это мой код:

class Person { 
    let age: Int

    init(age: Int) { 
        self.age = age
    }

    func callAgePrinter() { 
        // THIS LINE
        AgePrinter.printAgeOf(person: { return self } )
    }
}

class AgePrinter {
    static func printAgeOf(person: () -> (Person)) { 
        print(person().age)
    }
}

Person(age: 1).callAgePrinter()

Обратите внимание на комментарий: // THIS LINE

Я могу преобразовать эту строку:

AgePrinter.printAgeOf(person: { return self } )

Кому:

AgePrinter.printAgeOf(person: { [unowned self] in return self } )

Результат кода тот же.

Мне интересно: для чего неиспользуемые замыкания (которые применяются для Swift 4.2 только на уровне объявления функций), для чего используется список захвата?Для неэкранированных замыканий гарантируется, что после завершения метода, в котором замыкание вызывается (или не вызывается), замыкание исчезает и не сохраняется.

Конечно, при сохранении все еще может произойти цикл сохранениявывод закрытия в моем примере.Однако цикл захвата не препятствует этому.

Какое значение имеет включение (или не включение) списка захвата в неэкранированные замыкания?

Ответы [ 2 ]

2 голосов
/ 05 марта 2019

Обычно списки захвата используются для self, но это не единственная их цель. Список захвата захватывает произвольные значения. И под «захватом» я подразумеваю «создает собственную теневую копию, а не закрывает значение в своей области». Рассмотрим следующий код:

var a = 10

let f: () -> Void = { print("f: \(a)") }

let g: () -> Void = { [a] in print("g: \(a)") }

a = 20
f()   // f: 20; using "a" from the local scope surrounding f()
g()   // g: 10; using "a" that was copied into g()

В качестве немного более сложного примера рассмотрим следующий (неправильный) код, в котором мы накапливаем некоторые действия для выполнения, используя некоторое значение, которое необходимо увеличить от действия к действию:

var actions: [() -> Void] = []

var opId = 0
if someCase {
    opId += 1
    actions.append({ doSomethingWith(opId) })
}
if anotherCase {
    opId +=1
    actions.append({ doSomethingElseWith(opId) })
}
//...
actions.forEach { $0() }

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

actions.append({ [opId] in doSomethingWith(opId) })
2 голосов
/ 05 марта 2019

Capture копирует информацию внутри переменной внутри новой. Я имею в виду [unowned self] создает другую переменную self, которая на самом деле не является self.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...