NSOperationQueue和UITableView版本正在崩溃我的应用程序

时间:2011-09-07 13:28:05

标签: objective-c ios exc-bad-access nsoperation nsoperationqueue

这是迄今为止我一直困扰的最奇怪的问题。

我在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中有一些非常复杂的代码,我真的不知道从哪里开始调试它。我真的希望我不必逐行完成或重写整个事情。

关于我应该去哪看的任何指示?

2 个答案:

答案 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)