UINavigationController重复调用push导致访问错误
我有一个 TabView 应用程序,其中一个选项卡将 NavView 作为其视图之一。该视图有一个带有 TableView 的子视图来保存事件。我启用了导航栏右上角的“添加”按钮,并将 IBAction 分配给该按钮。
目标是显示一个页面来添加新事件,该事件由在实例化子类控制器类的实例时加载的 NIB 文件定义。我还从父导航控制器传递了 ManagedObjectContext。
这第一次有效,但第二次按下“添加”按钮时,出现 EXC_BAD_ACCESS 错误。我已经调试到将控制器推送到导航控制器上,并且我已经确认这就是发生异常的地方。我已通读文档,它说导航控制器将通过点击导航栏顶部提供的“后退”按钮来弹出控制器。我还知道,如果我尝试将相同的视图推入堆栈,则会发生未处理的异常。我什至尝试在推送之前弹出到根目录以清除堆栈,但在第二次推送时仍然出现异常。
我应该在其他地方手动弹出这个(即导航“后退”按钮实际上没有弹出这个)吗?我还确认导航控制器和新实例化的视图控制器的实例都不为空。
这是“添加”按钮的代码片段:
- (IBAction) addEvent: (id)sender {
// Here we'd instantiate an instance of our Add Event Controller to show the form that allows us to enter a new event.
// We'd add the context to the class from here so that it can get to our Core Data
EventEntryViewController *fvController = [[EventEntryViewController alloc] initWithNibName:@"AddEventView" bundle:nil];
fvController.managedObjectContext = self.managedObjectContext;
[self.navigationController pushViewController:fvController animated:YES];
[fvController release];
fvController = nil;
}
感谢您的帮助。
更新:
好的,我已经阻止了异常的发生。我尝试了一个非常简单的视图,其中没有任何内容,没有 IBOutlet 或 IBActions 以及没有属性的控制器类。这有效,所以我认为这一定是我的 EventEntryViewController 的问题。它没有做太多事情,并且回溯显示它在显示视图的内部正在死亡,所以我什至没有到达 loadView 方法,更不用说我的代码的任何其他部分了。我有一些类属性已在之前的加载中初始化,作为一个好公民,我在 viewDidUnload() 中释放了它们,并在 dealloc() 中释放了它们。当我注释掉我的类属性的 dealloc 时,它起作用了!
我对此感到困惑,并将 NSLog() 行放入 viewDidLoad()、viewDidUnload() 和 dalloc() 中。这是我取出类属性的 dalloc 之后的两个推送序列的结果:
2010-09-18 20:17:46.224 myFuel[6435:207] EventTableNavViewController: viewDidAppear
2010-09-18 20:17:51.391 myFuel[6435:207] **EventEntryViewController**: View Did Load // loading up my class
2010-09-18 20:17:53.954 myFuel[6435:207] EventTableNavViewController: viewWillAppear
2010-09-18 20:17:54.314 myFuel[6435:207] EventTableNavViewController: viewDidAppear
2010-09-18 20:17:54.315 myFuel[6435:207] **EventEntryViewController**: dalloc // after the class should have been popped
2010-09-18 20:18:02.803 myFuel[6435:207] **EventEntryViewController**: View Did Load //loading up my class
2010-09-18 20:18:08.134 myFuel[6435:207] EventTableNavViewController: viewWillAppear
2010-09-18 20:18:08.494 myFuel[6435:207] EventTableNavViewController: viewDidAppear
2010-09-18 20:18:08.495 myFuel[6435:207] **EventEntryViewController**: dalloc // after the class should have been popped
我在这里遗漏了什么吗?视图不应该调用 viewDidUnload() 从而释放类属性吗?我可以看到 dealloc 被调用,但我在哪里释放它们?
I have a TabView application with a tab that has a NavView as one of it's views. This view has a sub view with a TableView to hold events. I've enabled the "Add" button on the top right of the nav bar and assigned the IBAction to the button.
The objective is to show a page to add a new event which is defined by a NIB file loaded when I instantiate an instance of my subclassed controller class. I'm also passing down the managedObjectContext from the parent nav controller.
This works the first time, but the second time I push the "Add" button I get an EXC_BAD_ACCESS error. I've debugged through to the push of the controller onto the nav controller and I've confirmed this is where the exception occurs. I've read through the docs and it says that a nav controller will pop a controller by hitting the "back" button supplied at the top of the nav bar. I also know that an unhandled exception will occur if I try to push the same view onto the stack. I even tried popping back to root just before the push to clear the stack but still get the exception on the push the second time around.
Should I be popping this manually (i.e. the nav "back" button is not actually popping this) somewhere else? I've confirmed also that the instance of both the nav controller and the newly instantiated view controller are not empty.
Here's the code snippet for the Add Button:
- (IBAction) addEvent: (id)sender {
// Here we'd instantiate an instance of our Add Event Controller to show the form that allows us to enter a new event.
// We'd add the context to the class from here so that it can get to our Core Data
EventEntryViewController *fvController = [[EventEntryViewController alloc] initWithNibName:@"AddEventView" bundle:nil];
fvController.managedObjectContext = self.managedObjectContext;
[self.navigationController pushViewController:fvController animated:YES];
[fvController release];
fvController = nil;
}
Thanks for any help.
Update:
OK, I've stopped the exception from occurring. I tried a very simple view with nothing in it and no IBOutlets or IBActions and a controller class that had no attributes. That worked so I figured it had to be a problem with my EventEntryViewController. It didn't do much and a back trace showed it was dying on the internals of showing the view so I wasn't even getting to the loadView method let alone any other part of my code. I had a few class attributes that had been initialized in the previous load and as a good citizen I released them in viewDidUnload() and deallocated them in dealloc(). When I commented out the dealloc of my class attributes it worked!
I was confused by this and put NSLog() lines in viewDidLoad(), viewDidUnload() and dalloc(). Here's the results of the two push sequences after I took out the dallocs of my class attributes:
2010-09-18 20:17:46.224 myFuel[6435:207] EventTableNavViewController: viewDidAppear
2010-09-18 20:17:51.391 myFuel[6435:207] **EventEntryViewController**: View Did Load // loading up my class
2010-09-18 20:17:53.954 myFuel[6435:207] EventTableNavViewController: viewWillAppear
2010-09-18 20:17:54.314 myFuel[6435:207] EventTableNavViewController: viewDidAppear
2010-09-18 20:17:54.315 myFuel[6435:207] **EventEntryViewController**: dalloc // after the class should have been popped
2010-09-18 20:18:02.803 myFuel[6435:207] **EventEntryViewController**: View Did Load //loading up my class
2010-09-18 20:18:08.134 myFuel[6435:207] EventTableNavViewController: viewWillAppear
2010-09-18 20:18:08.494 myFuel[6435:207] EventTableNavViewController: viewDidAppear
2010-09-18 20:18:08.495 myFuel[6435:207] **EventEntryViewController**: dalloc // after the class should have been popped
Am I missing something here? Shouldn't the view have viewDidUnload() called thereby releasing the class attributes? I can see dealloc being called but where do I release these?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
根据您所说的,有几件事,尽管我不清楚您到底在做什么。
首先,不保证
viewDidUnload:
被调用。一般来说,只有当您的视图控制器为了响应内存警告而卸载它的视图时,它才会被调用。因此,您在viewDidLoad:
中保留的任何引用或任何连接的 IBOutlet 都应该在viewDidUnload:
和dealloc
中释放。其次,您说您“在 dealloc 中释放了它们”,这是指您的“类属性”,我认为这意味着您实际上是在其他对象上调用
dealloc
。如果是这样......不要这样做。您只能对保留的对象调用release
,并且在直接调用dealloc
时很少有实例。这是因为当最后一次释放对象时,dealloc
将在对象的release
实现中被调用。这就是保留/释放系统的全部要点。A couple of things based on what you've said, though I'm not clear exactly what you were doing.
First,
viewDidUnload:
is not guaranteed to get called. In general it will only get called if your view controller unloads it's view in response to a memory warning. As a result anything you retain references to inviewDidLoad:
or any IBOutlets hooked up should get released inviewDidUnload:
AND indealloc
.Second, you say you "deallocated them in dealloc" in reference to your "class attributes" which I take to mean you are actually calling
dealloc
on other objects. If so ... DO NOT DO THAT. You must only callrelease
on objects you have retained and will rarely ever have an instance when you are callingdealloc
directly. This is becausedealloc
will be called within an object's implementation ofrelease
when it is released for the last time. That is the whole point of the retain/release system.