UIViewController在被弹出时未被释放

4
我有一个表视图,当选择一个单元格时,它会将一个视图控制器推入导航栈中:
SAPostTableViewController *postViewController = [[SAPostTableViewController alloc] initWithNibName:NSStringFromClass([SAPostTableViewController class]) bundle:nil];
postViewController.site = site;
[self.navigationController pushViewController:postViewController animated:YES];
[postViewController release];

SAPostTableViewController具有静态tableView,其中的单元格是从nib中加载的。我已经重写了initWithNibName:bundle:方法:
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        self.sections = [NSMutableDictionary dictionary];
    }
    return self;
}

sections 是一个保留的属性。

SAPostTableViewControllerviewDidLoad 中我有这段代码:

- (void)viewDidLoad
{
    [super viewDidLoad];
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cellVisibiltyChanged:) name:@"SAStaticCellVisibiltyChanged" object:nil];
}

因此,为了匹配viewDidUnload

- (void)viewDidUnload
{
    [super viewDidUnload];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"SAStaticCellVisibiltyChanged" object:nil];
}

然而,当我按导航栏中的“返回”按钮(所有标准行为,没有覆盖)并弹出SAPostTableViewController时,它不会调用viewDidUnloaddealloc。这意味着如果我重新选择推送SAPostTableViewController的单元格,它将创建SAPostTableViewController的新实例,反复进行此操作只会导致内存使用量增加,因为弹出的SAPostTableViewController从未被释放。(我通过在分配上运行Instruments来了解这一点)
奇怪的是,如果我两次释放SAPostTableViewController,那么它就像我期望的那样工作:
SAPostTableViewController *postViewController = [[SAPostTableViewController alloc] initWithNibName:NSStringFromClass([SAPostTableViewController class]) bundle:nil];
postViewController.site = site;
[self.navigationController pushViewController:postViewController animated:YES];
[postViewController release];
[postViewController release];

如果我添加第三个释放语句,它会像我预期的那样崩溃,就像只有2个时一样。

我已经采用了使用retainCount并逐步执行直接上面代码行中执行的行的方法,在第一行代码执行完毕时,retainCount保持为1。它在第一行和第二行之间跳跃,所以我找不到任何地方会多保留它一次?

SAPostTableViewController仅在此处使用,它既不是任何东西的委托,也没有委托。

我该如何找到修复方法,或者是我忽略了简单的东西吗?

这是Instruments在推送SAPostTableViewController后仅一次显示的内容(仅有一个释放语句):

enter image description here

这是在反复导航回去和前进后Instruments显示的内容(同样,只有一个释放语句):

enter image description here

这里发生了什么:cellVisibiltyChanged。 - zahreelay
根据Instruments的数据,还有谁在使用SAPostTableViewController - Dave DeLong
似乎没有什么问题,我已经放了一张截图,显示了当我只有一个发布语句时仪器显示的内容。然后,如果我多次前后移动,它会显示什么。谢谢 :) - Jonathan.
我无法完全理解的两件事情是:什么。 - ott--
有两件事我无法完全理解:第一,NSStringFromClass() 除了返回一个字符串和 xib 名称有什么好处;第二, [NSMutableDictionary dictionary] - 你是不是想用 [[NSMutableDictionary alloc] init] - ott--
显示剩余3条评论
2个回答

0

当您单击一个单元格时,您正在创建一个新的对象,为什么不在初始化方法中创建您的对象(SAPostTableViewController),然后在每次单击单元格时推送相同的对象?

您可以这样做:

postViewController = [[SAPostTableViewController alloc] initWithNibName:NSStringFromClass([SAPostTableViewController class]) bundle:nil];

并且在

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
postViewController.site = site; 
[self.navigationController pushViewController:postViewController animated:YES]; [postViewController release]; 

    } 

因为每次都有完全不同的内容? - Jonathan.

0

我不知道你的问题是什么,但是有一些事情需要考虑:

  1. 绝对不要释放两次视图控制器。如果你确实发现了UIKit中的内存泄漏(这很不可能),那么它很可能会在将来的UIKit版本中得到修复。这意味着在新操作系统上运行旧版本的应用程序的任何人都会遇到崩溃(由于过度释放视图控制器)。泄漏的应用程序仍然可以使用(至少直到泄漏太多)。但是崩溃的应用程序根本无法运行。

  2. -viewDidUnload并不像你想象的那样工作。它只在视图控制器的视图由于内存压力而卸载时才被调用。它不会在正常释放期间调用。更明智的做法是依赖于-viewWillAppear:-viewDidDisappear:


所以,我应该在viewWillAppear中添加通知观察器,而不是在viewDidLoad中添加吗?当您在viewDidLoad中为通知添加观察器时,应该在哪里删除观察器? - Jonathan.
2
我终于找到问题了,我使用了addObserverForName:object:queue:usingBlock:(与我发布的代码分开),并且在块中使用了self,因此它不能被释放。 - Jonathan.
@Jonathan,最可靠的地方应该是-dealloc方法,但是只有在没有引入保留循环(retain cycle)的情况下才能起作用。 - Dave DeLong

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接