.sink { self.name = $0 } в self.cancellables — почему view model не освобождается и как это исправить?
Эта view model никогда не освобождается, даже после закрытия экрана, когда на неё уже ничто не ссылается.
final class ProfileViewModel {
@Published private(set) var name = ""
private var cancellables = Set<AnyCancellable>()
init(names: AnyPublisher<String, Never>) {
names.sink { value in
self.name = value // сильный захват self
}
.store(in: &cancellables)
}
}
Объясните, почему self не освобождается, и исправьте цикл удержания.
self владеет cancellables, тот — AnyCancellable, чьё замыкание sink сильно захватывает self — цикл удержания, поэтому self не освобождается. Исправьте списком захвата [weak self] или через assign(to: &$name), который self не захватывает.
- ✗Сильно захватывают
selfв замыканииsink, хранимом наself - ✗Винят
store(in:)или@Publishedвместо захвата в замыкании - ✗Забывают, что
assign(to: &$x)не захватываетself
- →Почему
assign(to: &$name)не создаёт цикл удержания? - →Когда
[unowned self]тут опаснее, чем[weak self]?
self owns cancellables, cancellables owns the AnyCancellable, and the sink closure captures self strongly — a retain cycle: self → cancellables → AnyCancellable → closure → self. Break it with a capture list:
init(names: AnyPublisher<String, Never>) {
names
.sink { [weak self] value in
self?.name = value
}
.store(in: &cancellables)
}
[weak self] (or .assign(to: &$name), which does not capture self at all) removes the strong edge, so the view model deallocates when its screen goes away.