EXC_BAD_ACCESS - NSFetchedResultsController、UITableViewController、UINavigationController、UIPopoverController
我在 UINavigationController
内有一个 UITableViewController
,在 UIPopoverController
内。
UITableViewController
使用 NSFetchedResultsController
。 didSelectRowAtIndexPath 将我的 UITableViewController
的另一个实例推送到导航控制器堆栈上,该实例的谓词略有不同。
如果我将一个新的 UITableViewController
推入堆栈,然后再次弹出它,如果我尝试保存一个会更新 tableview 的对象,我最终会得到一个 EXC_BAD_ACCESS
那被弹出了。
正如预期的那样,将我的 NSFetchedResultsController
的委托设置为 nil
可以消除 EXC_BAD_ACCESS
错误。
我正在使用ARC。很明显,这些对象正在被释放。这没关系。但为什么当有变化时他们仍然会收到通知?
代码如下。我基本上是在数据库中跟踪网络视图的历史记录。
BookmarkViewController * bookmarkController = [[BookmarkViewController alloc] initWithStyle:UITableViewStylePlain andWebView:self.webView];
UINavigationController * bookmarkNavController = [[UINavigationController alloc] initWithRootViewController:bookmarkController];
self.bookmarkPopover = [[UIPopoverController alloc] initWithContentViewController:bookmarkNavController];
_bookmarkPopover.popoverContentSize = CGSizeMake(320, 44*10);
_bookmarkPopover.delegate = self;
bookmarkController.container=_bookmarkPopover;
bookmarkController.delegate=self;
BookmarkViewController
使用 NSFetchedResultsController
,而 BookmarkViewController
是 NSFetchedResultsController
的委托
。
- (NSFetchedResultsController *) myFetchedResultsController
{
if (self.fetchedResultsController != nil) {
return self.fetchedResultsController;
}
// Singleton
CoreDataManager * dataManager = [CoreDataManager defaultDataManager];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Bookmark" inManagedObjectContext:dataManager.managedObjectContext];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"label" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:self.predicate];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setFetchBatchSize:20]; // Set the batch size to a suitable number.
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:dataManager.managedObjectContext
sectionNameKeyPath:@"type"
cacheName:nil];
self.fetchedResultsController.delegate = self;
return self.fetchedResultsController;
}
我还有:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
BookmarkViewController * bookmarkViewController = [[BookmarkViewController alloc] initWithStyle:self.tableView.style
andWebView:self.webview
forFolder:bookmark.label];
[self.navigationController pushViewController:bookmarkViewController animated:YES];
}
I have a UITableViewController
inside a UINavigationController
, inside a UIPopoverController
.
The UITableViewController
uses a NSFetchedResultsController
. didSelectRowAtIndexPath pushes another instance of my UITableViewController
with a slightly different predicate onto the nav controller stack.
If I push a new UITableViewController
on to the stack, and then pop it again, I will eventually get a EXC_BAD_ACCESS
if I try to save an object that would have updated the tableview that was popped off.
As expected, setting the delegate of my NSFetchedResultsController
to nil
removes the EXC_BAD_ACCESS
errors.
I am using ARC. So clearly these objects are getting released. This is OK. But why are they still getting notified when there is a change?
Code below. I am basically tracking the history of a web view in my database.
BookmarkViewController * bookmarkController = [[BookmarkViewController alloc] initWithStyle:UITableViewStylePlain andWebView:self.webView];
UINavigationController * bookmarkNavController = [[UINavigationController alloc] initWithRootViewController:bookmarkController];
self.bookmarkPopover = [[UIPopoverController alloc] initWithContentViewController:bookmarkNavController];
_bookmarkPopover.popoverContentSize = CGSizeMake(320, 44*10);
_bookmarkPopover.delegate = self;
bookmarkController.container=_bookmarkPopover;
bookmarkController.delegate=self;
The BookmarkViewController
uses an NSFetchedResultsController
and BookmarkViewController
is the delegate
of the NSFetchedResultsController
.
- (NSFetchedResultsController *) myFetchedResultsController
{
if (self.fetchedResultsController != nil) {
return self.fetchedResultsController;
}
// Singleton
CoreDataManager * dataManager = [CoreDataManager defaultDataManager];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Bookmark" inManagedObjectContext:dataManager.managedObjectContext];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"label" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:self.predicate];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setFetchBatchSize:20]; // Set the batch size to a suitable number.
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:dataManager.managedObjectContext
sectionNameKeyPath:@"type"
cacheName:nil];
self.fetchedResultsController.delegate = self;
return self.fetchedResultsController;
}
And also I have:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
BookmarkViewController * bookmarkViewController = [[BookmarkViewController alloc] initWithStyle:self.tableView.style
andWebView:self.webview
forFolder:bookmark.label];
[self.navigationController pushViewController:bookmarkViewController animated:YES];
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我发现了一些相关问题:
已释放视图由于获取的结果控制器更新,控制器导致 EXC_BAD_ACCESS
如果我发布,我的访问权限会很差,如果我保留,我泄漏
第二个链接给了我在 dealloc 方法中将委托设置为 nil 的想法
,但我使用的是 ARC,所以我无法显式调用
[super dealloc]
。似乎可以解决问题,但我不确定这是否正确。我是否还应该将其余的局部变量设置为nil?如果这覆盖了编译器生成的内容,它会泄漏吗?I found some related questions:
Deallocated view controller causing EXC_BAD_ACCESS because of fetched results controller update
If I release, I get bad access, if I retain, I leak
The 2nd link gave me the idea of setting the delegate to nil in the dealloc method
But I am using ARC so I cannot call
[super dealloc]
explicitly. Appears to fix the problem, but I am not sure this is correct. Should I also set the rest of my local variables tonil
? If this overrides what ever the compiler generates, will it leak?