iPhone / iOS popViewControllerAnimated 不刷新屏幕

发布于 2024-09-18 12:10:19 字数 2409 浏览 3 评论 0原文

当从 NSOperation 调用 .navigationController popViewControllerAnimated:YES 时,我遇到一个奇怪的问题,其中屏幕无法正确更新,并使弹出的视图可见,但显然已释放。

详细信息:我有一个访问本地 sqlite 数据库的列表视图。当点击一条记录时,它会显示该记录的详细信息视图,并启动异步 NSOperation(在主线程上)来检查 XML 后端数据库,以查看该记录在数据库中是否仍然可用。由于架构原因,我不会进入,我无法在列表视图上运行此操作,它必须在详细视图中。如果自上次同步后记录已被删除,它会通知用户该记录已被删除,并在共享应用委托上调用 popViewControllerAnimated。理想情况下,这将弹出当前详细信息视图并返回到上一个列表视图。

错误:正确的视图实际上已弹出到内存中(已被释放),但仍显示在屏幕上。导航栏是空白的,但我可以单击“后退”按钮应该在的位置,并且它会在列表视图之前导航到开始屏幕,这意味着至少导航栏知道它应该在哪里,即使如果它没有正确显示标题或后退按钮。主要问题是详细视图仍然可见并且可以与之交互,这会导致应用程序崩溃。例如,详细信息视图还在 UITableView 中显示数据,如果用户在表中向下滚动,则会引发异常“-[xAccountDetailController tableView:cellForRowAtIndexPath:]:消息发送到已释放的实例”

这让我相信详细控制器已通过 popViewControllerAnimated 调用正确释放,但显然有些东西仍然驻留在内存中,如果表实际上调用 cellForRowAtIndexPath,即使它的视图控制器已从导航控制器中弹出。

在详细视图中手动按下后退按钮(对于后端未删除的记录)效果很好。

解决方法尝试:当我向 NSOperation 传递对详细视图控制器的引用时,我尝试直接从该视图的 navigationController 属性和共享应用程序委托调用 popViewControllerAnimated。我还尝试弹出两个视图并将列表视图重新推送到导航控制器上,但这呈现出更令人不安的界面效果,其中根视图控制器和列表视图控制器似乎同时存在于导航栏中(标题相互覆盖)而不是不存在)。我尝试将对 NSOperation 中存在的详细视图控制器的引用设置为 nil,但这没有任何作用。我尝试在弹出之前调用 [detailView release] ,但正如预期的那样,它在弹出时失败,因为它在发布之前的保留计数仅为 1。我还尝试了 popToViewControllerpopToRootViewController ,但似乎没有任何效果。旧视图始终保留在那里,导航栏是唯一似乎可以执行任何操作的界面元素,即使如此,它也无法正确显示。我还尝试重新加载表,因为我真的不介意视图是否保持可见(不弹出),我只是想清除数据 - 但由于某种原因,表不会重新加载数据。

想法:由于运行 NSOperation 的操作队列是相关详细视图的属性,因此我已确保在详细视图的 dealloc 中取消 AllOperations 并将对操作队列的引用设置为 nil。我还尝试确保其他对象中对该视图的所有引用都已设置为零。直接从详细视图上的按钮调用 popViewControllerAnimated 效果非常好,因此我必须从 NSOperation 调用该方法,在 NSOperationQueue 上运行,这是我想要的详细视图的属性流行。某处的某些引用必须使该视图部分保持活动状态,但我似乎找不到在调用 pop 时仍然引用该视图的任何内容。

太多的地方有太多的代码,无法在这里发布。

有什么想法吗?

很抱歉问了这么长的问题,并提前致谢,

Greg


编辑 1: 我可以使用新的 UIViewController 轻松地在 NSOperation 之外重现此问题。

tableView:didSelectRowAtIndexPath 方法中,我调用以下内容:

xBaseViewController * vc = [[xBaseViewController alloc] initWithStyle:UITableViewStyleGrouped];
[self.navigationController pushViewController:vc animated:YES];
[vc performSelectorOnMainThread:@selector(popView) withObject:nil waitUntilDone:YES];

在 vc 中,popView 方法:

[self.navigationController popViewControllerAnimated:YES];

我认为这与保留计数或 NSOperation 无关。我以这种方式弹出视图是否犯了根本错误?

I have a strange issue when calling .navigationController popViewControllerAnimated:YES from an NSOperation where the screen does not properly update and leaves the popped view visible but apparently deallocated.

Details: I have a list view that accesses a local sqlite database. When tapping on a record, it displays that record's detail view and kicks off an asynchronous NSOperation (on the main thread) to check the XML back end database to see if that record is still available in the database. For architectural reasons I won't get into, I can't run this operation on the list view, it must be in the detail view. If the record was deleted since the last synchronization, it notifies the user that the record has been deleted and calls the popViewControllerAnimated on a shared app delegate. Ideally, this would pop the current detail view and return to the previous list view.

Error: The proper view is in fact popped in memory (it has been deallocated) but it is still displayed on the screen. The navigation bar is blank, but I can click on the place where the "back" button should be, and it navigates to the start screen prior to the list view, meaning that at least the navigation bar understands where it's supposed to be, even if it's not displaying the title or back buttons properly. The primary issue is that the detail view is still visible and can be interacted with, which causes the application to crash. For example, the detail view also displays data in a UITableView and if the user scrolls down in the table, an exception is thrown "-[xAccountDetailController tableView:cellForRowAtIndexPath:]: message sent to deallocated instance"

This leads me to believe that the detail controller has been deallocated properly by the popViewControllerAnimated call, but obviously something still resides in memory, if the table actually calls the cellForRowAtIndexPath, even though it's view controller has been popped off the navigationController.

Manually pushing the back button while on the Detail view (for a record that wasn't deleted on the back end) works perfectly.

Workaround attempts: As I pass in to the NSOperation a reference to the detail view controller, I have attempted to call the popViewControllerAnimated from that view's navigationController property directly and from the shared app delegate. I've also tried to pop two views and re-push the list view onto the navigationController but that presents an even more disturbing interface effect where the root and list view controllers appear to be existing simultaneously in the navigation bar (the titles overwrite each other rather than being nonexistent). I've tried to set the reference to the detail view controller that exists in the NSOperation to nil, but that does nothing. I've tried calling a [detailView release] prior to popping, but as expected, it fails on the pop because it only had a retain count of 1 prior to the release. I've also tried popToViewController and popToRootViewController and nothing seems to work. The old view is always still there, the navigation bar is the only interface element that seems to do anything, and even then, it's displaying incorrectly. I've also tried reloading the table, because I don't really mind if the view stays visible (no popping), I just want to clear the data -- but the table won't reloadData for some reason.

Thoughts: As the operationQueue that's running the NSOperation is a property of the detail view in question, I've made sure that in the detail view's dealloc to cancelAllOperations and to set the reference to the operationQueue to nil. I've also tried to make sure that all references to that view in other objects have been set to nil. Calling popViewControllerAnimated directly from a button on the detail view works perfectly, so it must be the fact that I'm calling that method from the NSOperation, running on an NSOperationQueue that's a property of the detail view I want to pop. Some reference somewhere must be keeping that view partially alive, but I can't seem to find anything that's still referencing the view when the pop is called.

There's too much code in too many places to post any here.

Any thoughts?

Sorry for such a long question and thanks in advance,

Greg


Edit 1:
I can reproduce this issue outside the NSOperation with a fresh UIViewController easily.

In a tableView:didSelectRowAtIndexPath method I call the following:

xBaseViewController * vc = [[xBaseViewController alloc] initWithStyle:UITableViewStyleGrouped];
[self.navigationController pushViewController:vc animated:YES];
[vc performSelectorOnMainThread:@selector(popView) withObject:nil waitUntilDone:YES];

In vc, the popView method:

[self.navigationController popViewControllerAnimated:YES];

I don't think this has to do with retain counts or the NSOperation. Am I doing something fundamentally wrong with popping the view in this manner?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

痴骨ら 2024-09-25 12:10:19

您的问题是您正在尝试在非主线程的线程上刷新屏幕。在iOS中,你只能用主线程更新屏幕上发生的事情。

您需要这样的代码:

[self performSelectorOnMainThread:@selector(mymethod) withObject:nil waitUntilDone:YES modes:nil];

并且它应该可以正常工作。

Your problem is that you are trying to refresh the screen on a thread that isn't the main thread. In the iOS, you can only update what is happening on the screen with the main thread.

You need code like this:

[self performSelectorOnMainThread:@selector(mymethod) withObject:nil waitUntilDone:YES modes:nil];

And it should work just dandy.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文