2010-09-13 119 views
1

NSOperation调用.navigationController popViewControllerAnimated:YES时出现一个奇怪的问题,屏幕没有正确更新,并且使弹出的视图可见但显然已解除分配。iPhone/iOS popViewControllerAnimated不刷新屏幕

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

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

这使我相信,细节控制器已经被解除分配通过调用popViewControllerAnimated正确,但显然仍有一些内存驻留在内存中,如果该表实际调用cellForRowAtIndexPath,即使它的视图控制器已经从navigationController中弹出。

在Detail视图中手动推回按钮(对于未在后端删除的记录)完美地工作。

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

想法:因为正在运行NSOperation的operationQueue是有问题的详细视图的一个属性,所以我确保在详细视图的dealloc中取消所有操作并将对operationQueue的引用设置为nil。我还试图确保在其他对象中对该视图的所有引用都设置为零。直接从详细视图上的按钮调用popViewControllerAnimated完美工作,所以它必须是我从NSOperation调用该方法,运行在NSOperationQueue上,这是我想要弹出的详细视图属性。某些地方的引用必须保持部分活动的视图,但我似乎无法找到任何仍在调用弹出窗口时引用该视图的内容。

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

有什么想法?

对不起,提前如此长的问题,谢谢,

格雷格


编辑1: 我可以重现这个问题的NSOperation外面用新鲜的UIViewController容易。

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做。以这种方式弹出视图,我在做一些根本性错误?

回答

2

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

你需要这样的代码:

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

它应该只是花花公子。

+0

感谢您的回答。我试过这个,但我似乎无法运行选择器。通过调试器,它到达这条线并跳过它。选择器调用过程中的断点永远不会被触发。正如预料的那样,将选择器名称更改为不存在的情况会导致程序崩溃,但使用正确的过程名称,它不会运行它。有任何想法吗? G – Greg 2010-09-13 17:50:41

+0

这对我一直都很有用,所以我不知道会出现什么问题,也许你应该拿掉模式部分,只使用'performSelectorOnMainThread:withObject:waitUntilDone:',但这只是一个可能的解决方案,因为我不知道你的代码中究竟做了什么。 – 2010-09-13 18:04:25

+0

再次感谢。离开'模式:'工作。但是,不幸的是没有解决问题。后退按钮向右移动,遗忘,我可以点击新的后退按钮,它会返回另一个视图,但导航栏是空白的,并且释放的视图仍然存在。 G – Greg 2010-09-14 10:21:59