I’m having some trouble with memory leaks on one of my view controllers. From my main view controller, I’m pushing my settings view controller like so:
-(IBAction)launchSettings {
SettingsViewController *svc = [[SettingsViewController alloc] init];
svc.title = @"title of app";
//this actually adds a back button for the next vc pushed
self.navigationItem.backBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStylePlain target:nil action:nil] autorelease];
[[self navigationController] pushViewController:svc animated:YES]; // <--Instruments says leak is here
[svc release];
if (AdsAreEnabled) {
ADBannerView *adBanner = SharedAdBannerView;
adBanner.delegate = nil;
}
}
So, when I initially push the view controller, I have no leaks. The view controller uses a GCD queue to load up my In-App Purchase store, and when I hit the “back” button I’ve created above to pop it off the stack, that’s when a crapload of leaks show up in Instruments. A bunch are showing up in the line of code where I push the view controller, which makes no sense to me since I immediately release it.
A couple other leaks are only leaking in main, either NSCFstrings, SKProduct and SKProductInternal, all of which I think are only brought up in the GCD queue. Here’s where instruments is telling me the problem is:
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil); // <-- Instruments says leak is here
[pool release];
return retVal;
}
Here’s my code where I call GCD, in its own method that gets called during viewDidLoad of the SettingsViewController:
if ([iapManager canMakePurchases]) {
// Display a store to the user.
iapTableView.sectionFooterHeight = 0;
iapTableView.rowHeight = 50;
iapTableView.scrollEnabled = NO;
//init sectionNames here to avoid leakage.
sectionNames = [[NSArray alloc] initWithObjects:@"Get Rid of Ads!", nil];
[spinner startAnimating];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadStore) name:kInAppPurchaseManagerProductsFetchedNotification object:iapManager];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadStore) name:kTransactionCompleted object:iapManager];
//Run this in seperate thread to avoid UI lockup
dispatch_queue_t store_check = dispatch_queue_create("see if store is available", NULL);
dispatch_async(store_check, ^ {
[iapManager loadStore];
});
dispatch_release(store_check);
}
I’m a little stumped as to what I’ve done wrong here – I use exactly the same technique to load up a different view controller and it doesn’t leak, and I can’t figure out how to tell if/where my GCD stuff is leaking – everything’s been analyzed repeatedly and comes out clean. I remove my observer from the Notification Center in SVC’s dealloc so it’s not that. I made sure to remove the transaction observer in my IAP manager’s dealloc, so it’s not that.
Any suggestions? Anything else you’d need to know to help me figure out where I’ve gone so terribly terribly wrong here?
Edited to add: I release sectionNames in SVC’s dealloc method, so that’s not it either.
Edit 2: I tried auto-releasing svc when I alloc it (and getting rid of the corresponding release) but I’m still getting the same leaks.
Well, I finally figured it out with some troubleshooting help from a friend – for some reason I forgot you still have to
releaseanIBOutletivar even if you haven’t set it up as aproperty(for some reason I thought anIBOutletautoreleasedif it wasn’t a property, which is not true), and once I had the proper releases indealloc, all my leaks magically went away.Duh. Another thing to add to my Idiot Checklist, I suppose. 🙂
Thanks for the suggestions, guys!