Можно ли хранить замыкания в массиве в Swift?

Ответ

Да, можно. В Swift замыкания (closures) являются first-class типами, что позволяет присваивать их переменным, передавать как аргументы и хранить в коллекциях, включая массивы.

Базовый пример:

// Массив замыканий, не принимающих и не возвращающих значений
var handlers: [() -> Void] = []

let handler1 = { print("Task 1 completed") }
let handler2 = { print("Task 2 completed") }

handlers.append(handler1)
handlers.append(handler2)

// Выполнить все замыкания
handlers.forEach { $0() }
// Вывод:
// Task 1 completed
// Task 2 completed

Практическое применение:

  • Цепочки обратных вызовов (callback chains)
  • Массивы обработчиков событий (например, кнопка с несколькими действиями)
  • Отложенное выполнение задач

Критически важные нюансы:

  1. Явное указание типа: Компилятору часто требуется явная аннотация типа массива.
  2. Циклы сильных ссылок: Если замыкание захватывает self, это создаёт сильную ссылку.

    // ❌ Риск утечки памяти
    closures.append { self.doSomething() }
    
    // ✅ Безопасный захват
    closures.append { [weak self] in
        self?.doSomething()
    }
  3. Изменяемость: Если массив объявлен как let, вы не сможете добавлять или удалять замыкания.

Ответ 18+ 🔞

А, ну ты про это! Да, конечно можно, чё за вопросы. В Swift замыкания — это как бы граждане первого сорта, их можно по переменным раскидать, в аргументы пихать и, само собой, в массивы складывать. Всё честно.

Смотри, элементарный пример:

// Массив замыканий, которые нихуя не принимают и нихуя не возвращают
var handlers: [() -> Void] = []

let handler1 = { print("Task 1 completed") }
let handler2 = { print("Task 2 completed") }

handlers.append(handler1)
handlers.append(handler2)

// Запускаем всю эту карусель
handlers.forEach { $0() }
// На экране:
// Task 1 completed
// Task 2 completed

А где это, блядь, пригождается?

  • Цепочки колбэков — когда одно за другим должно выполниться.
  • Куча обработчиков на одно событие — типа нажал кнопку, а там целый взвод действий.
  • Отложенные задачи — сложил в кучку, а потом разом запустил.

Но вот тут, сука, внимание, важные моменты, а то накосячишь:

  1. Тип указывай явно. Компилятор иногда тупит, как мартышлюшка, так что лучше ему помочь: [() -> Void].
  2. Циклы сильных ссылок — это пиздец. Если замыкание хватает self, то держись.

    // ❌ Так делать — гарантированно получить утечку памяти, ебать мои старые костыли.
    closures.append { self.doSomething() }
    
    // ✅ А вот так — правильно, по-взрослому.
    closures.append { [weak self] in
        self?.doSomething()
    }
  3. Изменяемость. Объявил массив как let — и всё, приехали. Ни добавить, ни удалить. Терпения ноль ебать, но правила есть правила.