При кодировании Swift всегда приятно наслаждаться статусом функций как первоклассных граждан. Это означает:

… F функции не отличаются от любой другой переменной. Функции могут использоваться как аргументы, могут быть возвращены как значения из других функций и могут быть присвоены переменной

Как и во всем остальном в жизни, с большой силой приходит большая ответственность. При использовании мощных заклинаний Свифта нужно очень внимательно относиться к циклам сохранения (даже самых хитрых). А теперь перейдем к делу:

APIRequestLayer.swift

Вышеупомянутый APIRequestLayer - это фиктивный класс, который немедленно вызывает свое закрытие responseReceived при вызове функции sendRequest. Обычно сетевая операция занимает некоторое время, и сразу после нее вызывается закрытие responseReceived. Но для простоты и сосредоточения внимания на сути я оставил это очень простым.

WorkerDelegate

Рабочий

Вышеупомянутый Worker также является еще одним фиктивным классом, который строго удерживает экземпляр APIRequestLayer и слабо содержит экземпляр WorkerDelegate.

Затем он устанавливает ссылку функции responseReceived на закрытие responseReceived APIRequestLayer. В функции responseReceived объекта Worker, WorkerDelegate ’ s вызывается один-единственный метод.

Вызов метода getResponseFromAPI ()

Чтобы запустить код, нам просто нужно инициализировать экземпляр Worker, вызвать для него метод getResponseFromAPI (), а затем установить для экземпляра Worker значение nil, чтобы посмотрим, выйдет ли он из памяти или нет.

Если мы видим строку «Deinit called» в области отладки Playground, то мы можем сказать, что переменная worker освобождена, и наоборот.

Эта проблема

Как видите, мы не использовали замыкания, не обращались к self. Но в настоящее время мы не видим «Deinit called» в области отладки игровой площадки из-за скрытого цикла сохранения. Самость фиксируется строго, потому что мы передаем ссылку функции responseReceived Worker на переменную responseReceive d APIRequestLayer.

Функция currying приходит на помощь

Чтобы решить проблему и позволить освободить экземпляр Worker из памяти, мы можем использовать каррирование функции. Первое изменение, которое мы должны сделать в классе Worker, выглядит следующим образом:

Приведенный выше код возвращает новую функцию (т.е. особый случай замыканий) из метода responseReceived . Таким образом, мы можем слабо захватить себя внутри возвращаемого замыкания. В области отладки мы видим, что напечатана строка Deinit called, что означает, что счетчик ссылок на рабочую переменную упал до нуля, и она удаляется из памяти ✌️