Swift: Closures (Замыкания)

Замыкания подобны блокам в Objective-C
Так называются блоки функциональности, захватывающие переменные из контекста
Синтаксис:
{ (parameters) -> returnType in
…//код
}

По большому счету это обрамленный в фигурные скобки тип функции + оператор in + тело функции
Бывает три разновидности замыканий
— глобальные функции — замыкание имеющее имя, и не захватывающее никаких значений
— вложенные функции, — замыкание имеющее имя и захватывающее значение из ограждающей ее функции
— легковесные замыкания без имени, захватывающие значения из окружающего их контекста

Запрещены к применению значения по умолчанию, variadic параметр разрешен только если он именован и помещен в конце списка параметров

Рассмотрим библиотечную функцию sorted (для swift 1.2) имеющую определение следующего вида

Для простоты перепишем определение проще в виде частного случая если бы sorted принимала только массив целых чисел

вторым параметром выступает тип функции isOrderedBefore:(Int, Int) -> Bool
Мы можем написать так

и вызвать sorted так


В Swift 2.0 вместо функции sorted ввели метод sort, так что нужно вызывать так

Но если вызов единственный и городить отдельную функцию для этого нецелесообразно? Тут и приходят на помощь замыкания

Swift 1.2


Swift 2.0

Но мы можем себе упростить жизнь, т.к. swift знает из определения функции sorted и переданного массива какого типа будут параметры и тип возвращаемого значения у типа функции — их можно опустить
Swift 1.2


Swift 2.0

В однострочном варианте можно опустить слово return

Swift 1.2


Swift 2.0

Можно так же опустить именование переменных и получить к ним доступ по индексу, опустив помимо всего прочего оператор in
Swift 1.2


Swift 2.0

Т.к. для Int определен оператор <, мы можем сократить все до этого варианта Swift 1.2

Swift 2.0

Если замыкание идет последним аргументом функции и оно имеет большое тело, его тело можно вынести за круглую скобку Было:

Стало

Ну или переписав наш пример Swift 1.2

Swift 2.0

Так же существует подводный камень в виде захвата переменных (capture values). Когда выполняется код создающий конкретное замыкание — он захватывает все необходимые переменные, чтобы данное замыкание могло существовать даже после выхода из текущего контекста

Таким образом при создании функции incrementer внутри функции addBy были захвачены переменная sum и константа number

Создав новый incrementBy3 мы убедились что переменная sum в нем не зависит от sum в предыдущем incrementBy5. Т.е. при каждом создании замыкания — в него захватывается текущее окружение.
Переменные захватываются по ссылке, а не по значению

Особенно важно помнить о захвате переменных при работе с Cocoa, где захват self может произойти совершенно незаметно и создаст сильную связь (strong reference), в итоге текущий объект и замыкание создадут классическую циклическую связь создав утечку памяти.

Ну и не забываем что замыкание — ссылочного типа.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *