这是迄今为止我一直困扰的最奇怪的问题。
我在UINavigationController上有一个UIViewController,我想使用NSInvocationOperation在viewDidAppear上调用一个方法,这样当视图变得可见时它可以在后台线程上运行。
问题是如果我弹出视图控制器 BEFORE 操作(在这种情况下 testMethod 方法)完成运行,应用程序崩溃。
如果我弹出视图控制器 AFTER ,一切运行正常。
当应用程序崩溃时,它会以“EXC-BAD-ACCESS”停在[super dealloc]并给我以下错误。
bool _WebTryThreadLock(bool),xxxxxxxxx:试图获取网络锁 从主线程或Web线程以外的线程。这可能 是从辅助线程调用UIKit的结果。崩溃 现在...
这是我的代码(超简化)..
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSInvocationOperation *theOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(testMethod) object:nil];
[operationQueue addOperation:theOperation];
[theOperation release];
}
- (void)testMethod
{
NSLog(@"do some stuff that takes a few seconds to complete");
}
- (void)dealloc
{
[_tableView release];
[super dealloc];
}
testMethod 有一些代码需要几秒钟才能完成。我只有一些线索,我真的不知道如何以及从哪里开始调试。
线索#1:最有趣的是,如果我删除了[_tableView版本];从dealloc然后应用程序不会崩溃。但当然这会导致泄漏,我无法将其删除。
线索#2:我在带有UITableView的单独“干净”UIViewController上测试了这段代码,令我惊讶的是没有崩溃。
线索#3:应用程序没有崩溃是在viewDidLoad中将UITableView的数据源设置为nil。
线索#4:如果我在viewDidAppear中使用与IBAction等其他地方相同的代码,应用程序似乎不会崩溃。
线索#5:我曾尝试使用NSZombie查看堆栈数据,但它为我提供了大量数据并且它无处可寻。
我的UITableViewDelegate和UITableViewDataSource中有一些非常复杂的代码,我真的不知道从哪里开始调试它。我真的希望我不必逐行完成或重写整个事情。
关于我应该去哪看的任何指示?
答案 0 :(得分:2)
问题可能是你的视图控制器的最后一个引用是保持它的操作队列,这意味着你在技术上调用(或有系统调用)后台线程中的一些UIKit方法(a操作清理时,大禁忌。
为防止这种情况发生,您需要在操作结束时在主线程上向控制器发送保持活动消息,方法是在testMethod
的最后一行添加类似的内容:< / p>
[self performSelectorOnMainThread:@selector(description) withObject:nil waitUntilDone:NO];
在操作队列释放视图控制器之前,仍有可能处理此消息,但这种可能性很小。如果它仍在发生,你可以这样做:
[self performSelectorOnMainThread:@selector(keepAlive:)
withObject:[NSNumber numberWithBool:YES]
waitUntilDone:NO];
- (void)keepAlive:(NSNumber *)fromBackground
{
if (fromBackground)
[self performSelector:@selector(keepAlive:) withObject:nil afterDelay:1];
}
通过在主线程上向视图控制器发送消息,它将使对象保持活动状态(NSObject保留视图控制器,直到主线程处理消息)。如果在延迟后执行选择器,它还会使视图控制器保持活动状态。
答案 1 :(得分:1)