При кодировании Swift всегда приятно наслаждаться статусом функций как первоклассных граждан. Это означает:
Как и во всем остальном в жизни, с большой силой приходит большая ответственность. При использовании мощных заклинаний Свифта нужно очень внимательно относиться к циклам сохранения (даже самых хитрых). А теперь перейдем к делу:
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, что означает, что счетчик ссылок на рабочую переменную упал до нуля, и она удаляется из памяти ✌️