在我的一个应用程序中,我提出了一个着陆视图控制器,如代码所示。这种方法很好,除了当我注销应用程序并重新登录时,调用相同的方法并最终创建一个新的MyLandingController
,保持旧的{1}}仍然存在。既然,我将它分配给一个属性不应该自动解除分配旧的属性吗?我检查并确保没有其他对象强烈引用MyLandingController
;虽然有弱的参考。
- (void)presentMyLandingView {
self.navigationController = nil;
[[self.window viewWithTag:100] removeFromSuperview];
self.window.backgroundColor = [UIColor whiteColor];
self.primaryViewController = [[MyLandingController alloc] init];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.primaryViewController];
[self.navigationController.navigationBar setBarStyle:UIBarStyleBlack];
[self.window insertSubview:[self.navigationController view] atIndex:1];
self.window.rootViewController = self.navigationController;
[NSTimer scheduledTimerWithTimeInterval:.50 target:self selector:@selector(clearSubviews) userInfo:nil repeats:NO];
}
作为一项临时工作,我想到了一个条件,即如果我的旧MyLandingController
存在,那么使用它而不是创建一个新的{{1}}。这可以修复泄漏,但整个视图向上移动(看起来像是通过导航栏大小向上移动)。
所以,我正在寻找2个问题的答案 -
Q1)为什么将新的视图控制器对象重新初始化为不取消分配旧对象的属性。
Q2)为什么重新使用现有对象(从弱引用中提取)不能很好地呈现UI - 屏幕向上移动?
答案 0 :(得分:1)
它泄漏是因为着陆控制器仍在显示堆栈中,因此它不会被释放 - 导航控制器仍然保留一个参考。
那巧合 - 回答了你的两个问题,因为视图控制器不应该在演示文件堆栈中两次。
您可以检查它是否存在,在这种情况下只是
[self.navigationController popToRootViewControllerAnimated:NO];
而不是创建另一个实例。
答案 1 :(得分:0)
由于最后一行存在内存泄漏:
[NSTimer scheduledTimerWithTimeInterval:.50 target:self selector:@selector(clearSubviews) userInfo:nil repeats:NO];
NSTimer
在无效之前会强烈引用其目标。来自Apple's documentation:
定时器触发时,aSelector指定的消息发送到的对象。计时器保持对该对象的强引用,直到它(计时器)无效为止。
在创建新计时器之前,必须使旧计时器无效,以消除内存泄漏。
- (void)presentMyLandingView {
[self.timer invalidate]; //invalidates the old timer
//rest of your code goes here
self.timer = [NSTimer scheduledTimerWithTimeInterval:.50 target:self selector:@selector(clearSubviews) userInfo:nil repeats:NO]; //keeps reference to the new timer so that it is possible to invalidate that timer later . Note that this should be a `weak` reference as the timer is retained by the run loop anyway.
}