Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storing weak reference sometimes causes leak

I have a class A that stores a optional weak variable to other object, that is a subclass of A. Sometimes when I store something in this variable I get a leak - this happens rarely, but it does. I'm assigning this variable in forEach loop, but I also found similar leak in other place of application once when using weak var, so I don't think that loop has anything to do with this. Responsible library is libswiftCore.dylib and responsible frame is swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::formWeakReference(). Did someone else have had similar issue? Is there some way I can fix this?

enter image description here

enter image description here

enter image description here

like image 954
Damian Dudycz Avatar asked Jul 14 '18 14:07

Damian Dudycz


People also ask

Why we use weak self in closure?

In Swift, [weak self] prevents closures from causing memory leaks in your application. This is because when you use [weak self], you tell the compiler to create a weak reference to self. In other words, the ARC can release self from memory when necessary.

Do you always need weak self?

Using [weak self] is only required within situations in which capturing self strongly would end up causing a retain cycle, for example when self is being captured within a closure that's also ultimately retained by that same object.

Why do we use unowned and weak self?

“Use a weak reference whenever it is valid for that reference to become nil at some point during its lifetime. Conversely, use an unowned reference when you know that the reference will never be nil once it has been set during initialisation.”


1 Answers

Try setting the variable instead of being weak set it to be unowned. This is a Swift bug sort of as there is no warning for the developer that he is capturing a strong reference of the nested closure, however, setting it to unowned should do as a workaround for now.

EDIT1: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001197.html

Mentioned as an improvement from here here:

class ViewControllerBase: UIViewController {
let timer:DispatchSourceTimer = DispatchSource.makeTimerSource(flags: [], queue:  DispatchQueue(label: "q.q"))

deinit {
    NSLog("deinit of \(NSStringFromClass(type(of: self)))")
}

override func viewDidLoad() {
    super.viewDidLoad()

    timer.scheduleRepeating(deadline: .now(), interval: .seconds(1))

    timer.setEventHandler {
        UIView.animate(withDuration: 0.2) { [weak self] in
            self?.view.backgroundColor = UIColor.green
        }
    }
}

This leaks memory in a subtle way...there is a retain loop even though self is only used in a "weak" manner. This is because the nested closure captures a strong reference for use in the closure that follows.

EDIT 2: I might be wrong but the OP is using changes.forEach closure and then another closure with changes.added.forEach I could be wrong but this might be the cause of the whole issue perhaps declaring it there [weak self] (cluster, change) in ... could possibly remove the issue. It is swifts built in closure but still a closure, that could technically cause them to be nested.

Try changing your code to:

changes.forEach{[weak self] (cluster, change) in

see if that helps

or

changes.forEach{[unowned self] (cluster, change) in

Also any chance that you could paste your code instead of doing a screenshot as it is easier to recreate your code instead of retyping it.

like image 178
AD Progress Avatar answered Sep 24 '22 18:09

AD Progress