Since you're doing this on the main run loop, you can (and should) simplify the ClockRun
method:
- (void)ClockRun {
self.time = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(check) userInfo:nil repeats:YES];
}
That NSInvocation
code was unnecessary and the NSRunLoop
code could only introduce problems.
Having said that, this is unlikely to be the source of your memory consumption. And nothing else in the provided code snippets looks like an obvious memory problem. If you're 100% confident that the timer is getting invalidated, then the timer is not the problem. I wonder about the object graph between the view controller at this mtClockController
. Or perhaps some circular reference in view controllers (e.g. pushing from A to B and to A again). It's hard to say on the basis of what's been provided thus far.
Sadly, there's not much else we can suggest other than the routine diagnostics. First, I'd run the the app through the static analyzer (by pressing shift+command+B in Xcode, or choosing "Profile" from the Xcode "Product" menu).
Second, you should run your app through Leaks and Allocations tools to identify the what precisely is leaking on each iteration. Do you have extra instances of the view controllers? Or just the mtClockController
?
Until you identify what's not being deallocated, it's hard to remedy it. And Instruments is the best tool for identifying what's not getting released. In WWDC 2012 video iOS App Performance: Memory the demonstration sections of the video give pragmatic demonstrations of using Instruments (as well as a wealth of good background info on memory management).
Third, when I've got a situation where I'm not sure if things are getting deallocated when they should, I sometimes include dealloc
methods that tell me when the object is deallocated, e.g.:
- (void)dealloc {
NSLog(@"%s", __PRETTY_FUNCTION__);
}
I'd suggest this not only for your key model objects, but your view controller, too. (Sometimes we agonize over our model objects only to realize that it's the view controller, itself, which is be retained by something else.)
Clearly Instruments is a much richer tool, but this can be used to quickly identify failure to deallocate (and show you what's maintaining the strong references).
I ran you app through Instruments, watching your custom objects, and everything is being deallocated properly. Below, I marked generation A, hit the button, let the timer expire, marked generation B, hit the button again, etc. I did that four times, and I then simulated a memory warning, and did one final generation. Everything looks fine (this is a compilation of six screen snapshots in one, showing the total allocations at each of the six generations):
I inspected your Generations, as well as the Allocations themselves, and none of your objects are in there. Everything is getting released fine. The only things there are internal Cocoa objects associated with UIKit
and NSString
. Cocoa Touch does all sorts of caching of stuff behind the scenes that we have no control over. The reason I did that final "simulator memory warning" was to give Cocoa a chance to purge what it can (and you'll see that despite what Generations reports, the total allocations fell back down a bit).
Bottom line, your code is fine, and there is nothing to worry about here. In the future, don't worry about incidentally stuff showing up in the generations, but rather focus on (a) your classes; and (b) anything sizable. But neither of those apply here.
In fact, if you restrict Instruments to only record information for your classes with the mt
prefix (you do this by stopping a recording of Instruments and tap on the "i" button on the Allocations graph and configure the "Recorded Types"), you'll see the sort of graph/generations that you were expecting: