assign(to: \.word, on: self)
and storing the resulting AnyCancellable
results in a strong reference cycle. Replacing assign(to:on:)
with assign(to: &$word)
prevents this problem
not sure why
assign(to: \.word, on: self)
and storing the resulting AnyCancellable
results in a strong reference cycle. Replacing assign(to:on:)
with assign(to: &$word)
prevents this problem
not sure why
@rpay_ios You create a strong reference cycle with assign(to:on:)
in Combine like this:
class Person {
var subscriptions = Set<AnyCancellable>()
@Published private var name: String = ""
private var fullName = ""
let nameSubject = PassthroughSubject<String, Never>()
func showFullName(for names: [String]) -> String {
nameSubject.assign(to: \.name, on: self).store(in: &subscriptions)
$name.sink{self.fullName.append("\($0) ")}
for name in names {
nameSubject.send(name)
}
fullName.removeFirst()
fullName.removeLast()
return fullName
}
deinit {
print("Goodbye \(fullName)!")
}
}
var me: Person? = Person()
let names = ["Cosmin", "George", "Pupăză"]
let fullName = me!.showFullName(for: names)
print("My full name is \(fullName).")
me = nil
The above block of code only prints My full name is Cosmin George Pupăză. to the console because you create a strong reference cycle in this case when you assign nameSubject
to name
in the showFullName(for:)
method. This means that the Person
class deinitializer doesn’t get called when you set me
to nil
because of that.
You can actually break the strong reference cycle in four different ways in Combine:
// original code
me!.subscriptions.removeAll()
me = nil
nameSubject
when you are finally done with it like this:// original code
me!.nameSubject.send(completion: .finished)
me = nil
subscriptions
as Set<AnyCancellable>?
in order to make it a weak property as follows:class Person {
var subscriptions: Set<AnyCancellable>? = Set()
// original code
func showFullName(for names: [String]) -> String? {
guard var subscriptions = subscriptions else {return nil}
// original code
}
// original code
}
var me: Person? = Person()
let names = ["Cosmin", "George", "Pupăză"]
if let fullName = me!.showFullName(for: names) {
print("My full name is \(fullName).")
} else {
print("No full name for me!")
}
me = nil
assign(to:)
in order to connect nameSubject
with name
in the showFullName(for:)
method like this:func showFullName(for names: [String]) -> String {
nameSubject.assign(to: &$name)
// original code
}
All of the above four solutions print Goodbye Cosmin George Pupăză! to the console since there is no strong reference cycle anymore so the Person
class deinitializer gets called this time.
Please let me know if you have any questions or issues about the whole thing when you get a chance. Thank you!
thanks for your kind explanation.
but I want to know why the strong reference can be caused.