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

Ответ

Да. Замыкания являются ссылочными типами и могут быть присвоены свойствам класса или структуры.

Ключевой аспект — управление памятью. Если замыкание захватывает self, необходимо предотвратить сильные циклические ссылки (retain cycles).

Пример безопасной реализации:

class MyClass {
    var closure: (() -> Void)?

    init() {
        // Используем weak capture, чтобы избежать retain cycle
        closure = { [weak self] in
            self?.doSomething()
        }
    }

    private func doSomething() {
        print("Action performed")
    }
}

Рекомендации:

  • Всегда используйте [weak self] или [unowned self], если замыкание, хранимое как свойство, захватывает self.
  • Тип свойства должен соответствовать сигнатуре замыкания (например, (() -> Void)?).

Ответ 18+ 🔞

Ну, слушай, вот смотри, как это бывает. Ты пишешь класс, всё у тебя красиво, замыкание там, логика... А потом — бац! — приложение как ляжет, а ты сидишь и чешешь репу: "Ну что за хуйня?". А это, блядь, retain cycle подкрался, как маньяк в подворотне.

Так вот, да, замыкания — это ссылочные типы, их можно тыкать куда угодно, хоть в свойство класса. Но вся соль, ёпта, в управлении памятью. Если твоё замыкание, хранимое в классе, вдруг возьмёт и схватит self — всё, пиши пропало. Круговая порука получается: класс держит замыкание, замыкание держит класс, и оба они смотрят друг на друга, как два идиота, и ждут, когда же их отпустят. А сборщик мусора машет им ручкой: "Ребята, вы же друг за друга держитесь, я вас не могу!"

Чтобы не было этой ебанины, надо ловить self аккуратно. Слабенько так, без фанатизма.

Смотри, как надо делать, если не хочешь потом волосы на жопе рвать:

class MyClass {
    var closure: (() -> Void)?

    init() {
        // Смотри сюда, самый важный момент, блядь!
        // Ловим self, но [weak]'ом, как хитрожопый кот мясо из холодильника.
        closure = { [weak self] in
            // А тут уже безопасно дергаем метод, но через вопросик.
            // Если self уже помер — ну и хуй с ним, просто тихо сдохнем.
            self?.doSomething()
        }
    }

    private func doSomething() {
        print("Action performed")
    }
}

Вот и вся магия, ёбана. Запомни, как "Отче наш":

  • Если замыкание живёт в свойстве и тыкается в selfобязательно вешай [weak self] или, в крайнем случае, [unowned self] (но это уже как русская рулетка, один раз проебёшься).
  • И да, сигнатура свойства должна точно совпадать с тем, что ты в замыкании городишь. Нельзя (() -> Void)? присвоить (Int) -> String, это ж не пазл, блядь, чтобы тыкать наугад.

Следуй этим простым правилам, и твои объекты будут умирать красиво и вовремя, а не висеть в памяти, как призраки в заброшенном замке.