2

I manually created a memory leak, but the Debug Memory Graph cannot detect it. This only happens on the controller, not on the general object type. Any one konw why? enter image description here

This is the code I used

import UIKit
class ViewController: UIViewController {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        present(Demo(), animated: true, completion: nil)
    }
}
class Demo : UIViewController {
    var obj:Demo?
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemTeal
        obj = self
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        dismiss(animated: true, completion: nil)
    }
}
Paulw11
  • 108,386
  • 14
  • 159
  • 186
chdo
  • 39
  • 7
  • 1
    Not exactly a dup, but very much: https://stackoverflow.com/questions/21831009/what-is-the-difference-between-leaks-and-allocations-living-in-instrumen/56265569#56265569. Tldr: There are **3** types of memory issues. Leaks, abandoned memories and cached memory. The memory debugger will ONLY show a _purple_ indicator for leaks. Basically anytime it sees two strong references pointing back to one another it will know it will cause it a leak. (1/2) – mfaani Sep 05 '21 at 16:09
  • However for **abandoned memory** e.g. notificationCenter issue you have, 2 objects are not strongly pointing to one another. It's just a _root path_ (Notification Center) which remains in memory all the time is pointing to an object and never letting go. For such memory issues, you won't see the purple indicator. Yet by going through the flow a few times, you'd see an increased _number_ of unreleased instances of the related classes. ie if you repeat the flow you'd see `(2)` instead of `(1)` for the number of classes you have.Because each time it strongly referenced by notificationCenter (2/2) – mfaani Sep 05 '21 at 16:09
  • @Honey unfortunatly it's not a case of **abandoned memory** because when we call addObserver the **NSNotificationCenter** creates **__NSObserver** wrapper that have weak reference to our class instance. – Mark Sep 05 '21 at 19:58
  • If it hold's Demo View Controller with strong reference the elimination of **obj = self** wouldn't fix the leak. But we see that it helps. – Mark Sep 05 '21 at 20:03
  • it seems that `NSNotificationCenter` covered this `Demo` object leak. – chdo Sep 06 '21 at 02:29
  • @Mark it still strongly holds onto the _token_. See [here](https://stackoverflow.com/questions/61344541/how-to-removeobserver-in-swift-5-using-addobserver-closure-method/61395815#61395815). Also for the Block based, you still have to be considerate of using `weak` yourself, as the observer keeps sending messages... – mfaani Sep 07 '21 at 13:21
  • @Honey We discuss selector based case, not closure one. For selector based method addObserver from apple documentation: "If your app targets iOS 9.0 and later or macOS 10.11 and later, you do not need to unregister an observer that you created with this function. If you forget or are unable to remove an observer, the system cleans up the next time it would have posted to it." If a selector based observer would create token that hold a strong reference, the deinit method of our object wouldn't be called, in normal case where isn't any another memory leaks. It's a Proof by contradiction. – Mark Sep 07 '21 at 17:17

1 Answers1

1

It's look like that UIViewController begin observation of UIApplicationSuspendedNotification.

There is 2 method to begin of observations:

  1. addObserver(_:selector:name:object:)
  2. addObserver(forName:object:queue:using:) Both keep weak reference to our Demo view controller. Demo vc is addObserver through first method. It's seems that apple didn't consider as memory leaks object's that observing NotificationCenter.

I get this information through follow debugging steps:

1. After opening debugger with enabled with enabled Malloc Stack Logging in project scheme i find out __NSObservers references. enter image description here

2. Then i look at Backtrace and find out that there is a calls to [NSNotificationCenter addObserver:selector:name:object:]. enter image description here

  1. Im added sybmolic breakpoint with method name [NSNotificationCenter addObserver:selector:name:object:] and printed all argument $arg1 $arg2 $arg3 $arg4 $arg5 $arg6 and find the name of observation.

  2. Using the address of NotificationCenter and and adress of my ViewController, i'm deleted the observation through [ NotificationCenterAdress removeObserver:ViewControllerAdress] and reopened memory debugger. And debugger treats viewController as memory leak. (there is 12 instances on screenshot because i taped on background multiple times). enter image description here

Mark
  • 701
  • 6
  • 12