简体   繁体   中英

Confused why this doesn't cause a memory leak?

I noticed the other day my iOS app is leaking memory like a sieve (I wrote some automated tests that did long run thrashing and then I noticed the app just grows in size until it dies).

I had long suspected, that I was going to get more disciplined about closure variables. So I've spent the day trying to figure out where my app is leaking memory. The Xcode tools so far haven't been much help.

A while ago I had my own Ticker (a periodic timer) object:

class Ticker {
    // MARK: - Properties Stored
    var interval:Duration = 1.seconds
    private var queue = DispatchQueue.main
    private var source: DispatchSourceTimer!
    var tick:()->() = {}

    // MARK: - accessing
    func start() {
        self.stop()
        self.source = DispatchSource.makeTimerSource(queue: self.queue)
        let nsgap = DispatchTimeInterval.microseconds(Int(self.interval.microseconds.rounded().magnitude))
        self.source.schedule(deadline: DispatchTime.now() + nsgap, repeating: nsgap, leeway: DispatchTimeInterval.seconds(0))
        self.source.setEventHandler(handler: self.tick)
        self.source.resume()
    }

    func stop() {
        if self.source != nil {
            self.source.cancel()
            self.source = nil
        }
    }
}

Then I have a UIController subclass that first has one of these as a variables:

class MyController: UIViewController {
    var scanTimer:Ticker = Ticker()
    ...

And later has a method that looks like this:

@IBAction func startScanning() {
    self.stopScanning()
    ...
    self.scanTimer = Ticker()
    self.scanTimer.interval = 500.milliseconds
    var tickCount = 0
    self.scanTimer.tick = {
        tickCount += 1
        if tickCount > 20 {
             self.stopScanning()
        }
        if self.bleBecameActive {
            self.bleBecameActive = false
            self.startBLEScan()
        }
    }
    self.scanTimer.start()
}

The way I understand things... my controller has a hard reference to the timer. The timer has a hard reference to a closure (the tick variable). And the closure has a reference to self. Shouldn't that create a cycle?

But the Debug Memory Graph doesn't show this as an issue at all. Why not? Is it a) not really an issue or b) the tool isn't doing what I think it is?

In this instance, I generally leverage Abandoned Memory to identify the underlying issue. Though this article is very old, it talks about how to go over it. After doing the same interaction multiple times, check for the classes that your app creates (not the system ones) that are not getting released.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM