PushViewController 中的内存泄漏和(我认为)从 GCD 队列返回
我的一个视图控制器上出现内存泄漏问题。从我的主视图控制器中,我像这样推送我的设置视图控制器:
-(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;
}
}
因此,当我最初推送视图控制器时,我没有泄漏。视图控制器使用 GCD 队列来加载我的应用内购买商店,当我点击上面创建的“后退”按钮将其从堆栈中弹出时,仪器中就会出现大量泄漏。在我推送视图控制器的代码行中出现了一堆,这对我来说毫无意义,因为我立即释放了它。
其他几个泄漏仅在 main 中泄漏,NSCFstring
、SKProduct
和 SKProductInternal
,我认为所有这些都只在GCD 队列。这是仪器告诉我问题所在的地方:
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;
}
这是我调用 GCD 的代码,在它自己的方法中,该方法在 SettingsViewController
的 viewDidLoad
期间被调用:
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);
}
我有点困惑于我在这里做错了什么 - 我使用完全相同的技术来加载不同的视图控制器并且它不会泄漏,而且我不知道如何判断我的 GCD 内容是否/在哪里泄漏 -一切的经过反复分析,结果是干净的。我从 SVC 的 dealloc
的通知中心删除了我的观察者,所以事实并非如此。我确保在 IAP 管理器的 dealloc
中删除了事务观察器,所以事实并非如此。
有什么建议吗?你还需要知道什么来帮助我弄清楚我在哪里犯了如此严重的错误吗?
编辑添加:我在 SVC 的 dealloc
方法中释放了sectionNames,所以这也不是它。
编辑2:我尝试了自动释放
当我alloc
它时(并摆脱相应的release
),但我仍然遇到相同的泄漏。
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 NSCFstring
s, 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好吧,在朋友的一些故障排除帮助下,我终于弄清楚了 - 由于某种原因,我忘记了即使您还没有设置它,您仍然必须
release
一个IBOutlet
ivar作为一个属性
(出于某种原因,我认为如果它不是一个属性,那么它是一个IBOutlet
autoreleased
,这是不正确的),并且一次我有正确的版本dealloc
,我所有的泄漏都神奇地消失了。呃。我想,还有一件事要添加到我的白痴清单中。 :)
谢谢你们的建议,伙计们!
Well, I finally figured it out with some troubleshooting help from a friend - for some reason I forgot you still have to
release
anIBOutlet
ivar even if you haven't set it up as aproperty
(for some reason I thought anIBOutlet
autoreleased
if 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!
首先,在“启动设置”中。您已通过“alloc and init”初始化了 UIBarButtonItem,这使其保留计数 = 1,但您尚未释放它。
您应该意识到这些属性保留了传递给它们的值。所以你可以
自动释放
它。我应该说这个动作是不需要的,因为后退按钮已经为你设置好了。
其次,在最后一个代码片段中,您执行了相同的
sectionsName
。First of all, in "launchSettings". You have initialized the UIBarButtonItem by "alloc and init" which makes its retain count = 1 but you haven't released it.
You should realize that those properties are retaining the values passed to them. So you could have
autoreleased
it.I should say that this action isn't needed as the back button is already put for you.
Second, in the last code snippet, you did the same
sectionsName
.