Ваша программа может иметь цикл сохранения без утечки памяти.
Ваша программа имеет некоторые «корневые» значения: глобальные переменные, переменные в стеке и локальные переменные потока. Ваша программа может получить доступ к любому из этих значений «с нуля», не обращаясь к нему из какого-либо другого объекта.
Тогда ваша программа имеет другие объекты, доступные в качестве свойств объектов root: «дети» Корней. И у него есть объекты, достижимые из свойств детей: «внуки» корней. И так далее. Некоторые объекты достижимы несколькими путями из корней.
Таким образом, ваша программа имеет набор достижимых объектов: корни и все их потомки.
Любой объект, который ваша программа выделяла и не освобождала , и которого больше нет в наборе достижимости, утечка.
Теперь давайте посмотрим на код в вашем вопросе.
Утечка self
? Вы не сказали, что такое self
. Если на него ссылаются из глобальной переменной, или он находится в иерархии представления (или контроллера представления) или иным образом доступен, он не просочился.
Утечка издателя? Издатель, созданный вами с Timer.publish(...).autoconnect().map{...}.assign(...)
, не пропущен. Он содержит ссылки на self
, но уничтожается при возврате initTimePublisher
.
Не утечка AnyCancellable
, хранящегося в subs
? Если self
не пропущено, то AnyCancellable
достижимо, и поэтому оно также не пропущено.
Теперь вы можете быть смущены, потому что я сказал, что издатель уничтожен, когда initTimePublisher
возвращается. Но вы все еще получаете сигналы от таймера, верно?
Когда вы звоните .assign(to:on:)
(или .sink
), вы создаете Subscription
. Фактически, вы создаете график объектов Subscription
, который обычно отражает график объектов Publisher
, на которые вы подписаны. Вот ваш Publisher
график:
Timer.Publisher <- Autoconnect <- Map
И поэтому, когда вы подписываетесь с помощью оператора .assign
, вы получаете Subscription
график, который выглядит следующим образом:
Timer.Publisher.Subscription <- Autoconnect.Subscription <- Map.Subscription
<- Assign.Subscription
( Под капотом Combine обычно использует имя типа Conduit
или Inner
для типа Subscription
, так что это то, что вы увидите в инспекторе памяти или при отладочной печати.)
AnyCancellable
вы вернетесь из .assign
, который храните в subs
, - это обертка вокруг Assign.Subscription
.
Итак, на графике подписки есть циклы сохранения. Объект Map.Subscription
содержит замыкание, переданное вами в .map
, которое содержит ссылку на self
. И Assign.Subscription
содержит ссылку на self
и ссылку на Map.Subscription
. И self
содержит subs
, который содержит AnyCancellable
, обертывающий Assign.Subscription
.
Но все эти объекты все еще достижимы, но не просочились, пока self
достижим.
Если вы удаляете AnyCancellable
из subs
и позволяете ему быть уничтоженным, то он вызывает cancel
на Assign.Subscription
. Это говорит Assign.Subscription
об отказе от ссылки на self
и отмене восходящей подписки Map.Subscription
. Затем Map.Subscription
отбрасывает свою ссылку на закрытие и отменяет свою восходящую подписку. И так далее. Как только отмена распространяется вплоть до Timer.Publisher.Subscription
, все циклы сохранения были прерваны, и все Subscription
объекты были очищены. Нет утечек.